github.com/opentofu/opentofu@v1.7.1/internal/cloud/migration.go (about) 1 // Copyright (c) The OpenTofu Authors 2 // SPDX-License-Identifier: MPL-2.0 3 // Copyright (c) 2023 HashiCorp, Inc. 4 // SPDX-License-Identifier: MPL-2.0 5 6 package cloud 7 8 import ( 9 "github.com/opentofu/opentofu/internal/configs" 10 legacy "github.com/opentofu/opentofu/internal/legacy/tofu" 11 ) 12 13 // Most of the logic for migrating into and out of "cloud mode" actually lives 14 // in the "command" package as part of the general backend init mechanisms, 15 // but we have some cloud-specific helper functionality here. 16 17 // ConfigChangeMode is a rough way to think about different situations that 18 // our backend change and state migration codepaths need to distinguish in 19 // the context of Cloud integration mode. 20 type ConfigChangeMode rune 21 22 //go:generate go run golang.org/x/tools/cmd/stringer -type ConfigChangeMode 23 24 const ( 25 // ConfigMigrationIn represents when the configuration calls for using 26 // Cloud mode but the working directory state disagrees. 27 ConfigMigrationIn ConfigChangeMode = '↘' 28 29 // ConfigMigrationOut represents when the working directory state calls 30 // for using Cloud mode but the working directory state disagrees. 31 ConfigMigrationOut ConfigChangeMode = '↖' 32 33 // ConfigChangeInPlace represents when both the working directory state 34 // and the config call for using Cloud mode, and so there might be 35 // (but won't necessarily be) cloud settings changing, but we don't 36 // need to do any actual migration. 37 ConfigChangeInPlace ConfigChangeMode = '↻' 38 39 // ConfigChangeIrrelevant represents when the config and working directory 40 // state disagree but neither calls for using Cloud mode, and so the 41 // Cloud integration is not involved in dealing with this. 42 ConfigChangeIrrelevant ConfigChangeMode = '🤷' 43 ) 44 45 // DetectConfigChangeType encapsulates the fiddly logic for deciding what kind 46 // of Cloud configuration change we seem to be making, based on the existing 47 // working directory state (if any) and the current configuration. 48 // 49 // This is a pretty specialized sort of thing focused on finicky details of 50 // the way we currently model working directory settings and config, so its 51 // signature probably won't survive any non-trivial refactoring of how 52 // the CLI layer thinks about backends/state storage. 53 func DetectConfigChangeType(wdState *legacy.BackendState, config *configs.Backend, haveLocalStates bool) ConfigChangeMode { 54 // Although externally the cloud integration isn't really a "backend", 55 // internally we treat it a bit like one just to preserve all of our 56 // existing interfaces that assume backends. "cloud" is the placeholder 57 // name we use for it, even though that isn't a backend that's actually 58 // available for selection in the usual way. 59 wdIsCloud := wdState != nil && wdState.Type == "cloud" 60 configIsCloud := config != nil && config.Type == "cloud" 61 62 // "uninit" here means that the working directory is totally uninitialized, 63 // even taking into account the possibility of implied local state that 64 // therefore doesn't typically require explicit "tofu init". 65 wdIsUninit := wdState == nil && !haveLocalStates 66 67 switch { 68 case configIsCloud: 69 switch { 70 case wdIsCloud || wdIsUninit: 71 // If config has cloud and the working directory is completely 72 // uninitialized then we assume we're doing the initial activation 73 // of this working directory for an already-migrated-to-cloud 74 // remote state. 75 return ConfigChangeInPlace 76 default: 77 // Otherwise, we seem to be migrating into cloud mode from a backend. 78 return ConfigMigrationIn 79 } 80 default: 81 switch { 82 case wdIsCloud: 83 // If working directory is already cloud but config isn't, we're 84 // migrating away from cloud to a backend. 85 return ConfigMigrationOut 86 default: 87 // Otherwise, this situation seems to be something unrelated to 88 // cloud mode and so outside of our scope here. 89 return ConfigChangeIrrelevant 90 } 91 } 92 93 } 94 95 func (m ConfigChangeMode) InvolvesCloud() bool { 96 switch m { 97 case ConfigMigrationIn, ConfigMigrationOut, ConfigChangeInPlace: 98 return true 99 default: 100 return false 101 } 102 } 103 104 func (m ConfigChangeMode) IsCloudMigration() bool { 105 switch m { 106 case ConfigMigrationIn, ConfigMigrationOut: 107 return true 108 default: 109 return false 110 } 111 }