commit
bbd8b48251
|
@ -98,8 +98,14 @@ func NewState() *State {
|
|||
// the given path. If the path is "root", for example, then children
|
||||
// returned might be "root.child", but not "root.child.grandchild".
|
||||
func (s *State) Children(path []string) []*ModuleState {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
// TODO: test
|
||||
|
||||
return s.children(path)
|
||||
}
|
||||
|
||||
func (s *State) children(path []string) []*ModuleState {
|
||||
result := make([]*ModuleState, 0)
|
||||
for _, m := range s.Modules {
|
||||
if len(m.Path) != len(path)+1 {
|
||||
|
@ -120,8 +126,15 @@ func (s *State) Children(path []string) []*ModuleState {
|
|||
// This should be the preferred method to add module states since it
|
||||
// allows us to optimize lookups later as well as control sorting.
|
||||
func (s *State) AddModule(path []string) *ModuleState {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
return s.addModule(path)
|
||||
}
|
||||
|
||||
func (s *State) addModule(path []string) *ModuleState {
|
||||
// check if the module exists first
|
||||
m := s.ModuleByPath(path)
|
||||
m := s.moduleByPath(path)
|
||||
if m != nil {
|
||||
return m
|
||||
}
|
||||
|
@ -140,6 +153,13 @@ func (s *State) ModuleByPath(path []string) *ModuleState {
|
|||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
return s.moduleByPath(path)
|
||||
}
|
||||
|
||||
func (s *State) moduleByPath(path []string) *ModuleState {
|
||||
for _, mod := range s.Modules {
|
||||
if mod.Path == nil {
|
||||
panic("missing module path")
|
||||
|
@ -155,6 +175,14 @@ func (s *State) ModuleByPath(path []string) *ModuleState {
|
|||
// returning their full paths. These paths can be used with ModuleByPath
|
||||
// to return the actual state.
|
||||
func (s *State) ModuleOrphans(path []string, c *config.Config) [][]string {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
return s.moduleOrphans(path, c)
|
||||
|
||||
}
|
||||
|
||||
func (s *State) moduleOrphans(path []string, c *config.Config) [][]string {
|
||||
// direct keeps track of what direct children we have both in our config
|
||||
// and in our state. childrenKeys keeps track of what isn't an orphan.
|
||||
direct := make(map[string]struct{})
|
||||
|
@ -168,7 +196,7 @@ func (s *State) ModuleOrphans(path []string, c *config.Config) [][]string {
|
|||
|
||||
// Go over the direct children and find any that aren't in our keys.
|
||||
var orphans [][]string
|
||||
for _, m := range s.Children(path) {
|
||||
for _, m := range s.children(path) {
|
||||
key := m.Path[len(m.Path)-1]
|
||||
|
||||
// Record that we found this key as a direct child. We use this
|
||||
|
@ -228,6 +256,8 @@ func (s *State) Empty() bool {
|
|||
if s == nil {
|
||||
return true
|
||||
}
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
return len(s.Modules) == 0
|
||||
}
|
||||
|
@ -238,6 +268,9 @@ func (s *State) IsRemote() bool {
|
|||
if s == nil {
|
||||
return false
|
||||
}
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if s.Remote == nil {
|
||||
return false
|
||||
}
|
||||
|
@ -258,6 +291,9 @@ func (s *State) IsRemote() bool {
|
|||
// If this returns an error, then the user should be notified. The error
|
||||
// response will include detailed information on the nature of the error.
|
||||
func (s *State) Validate() error {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
var result error
|
||||
|
||||
// !!!! FOR DEVELOPERS !!!!
|
||||
|
@ -295,6 +331,9 @@ func (s *State) Validate() error {
|
|||
// all children as well. To check what will be deleted, use a StateFilter
|
||||
// first.
|
||||
func (s *State) Remove(addr ...string) error {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
// Filter out what we need to delete
|
||||
filter := &StateFilter{State: s}
|
||||
results, err := filter.Filter(addr...)
|
||||
|
@ -362,7 +401,7 @@ func (s *State) removeModule(path []string, v *ModuleState) {
|
|||
|
||||
func (s *State) removeResource(path []string, v *ResourceState) {
|
||||
// Get the module this resource lives in. If it doesn't exist, we're done.
|
||||
mod := s.ModuleByPath(path)
|
||||
mod := s.moduleByPath(path)
|
||||
if mod == nil {
|
||||
return
|
||||
}
|
||||
|
@ -420,6 +459,16 @@ func (s *State) Equal(other *State) bool {
|
|||
return s == other
|
||||
}
|
||||
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
return s.equal(other)
|
||||
}
|
||||
|
||||
func (s *State) equal(other *State) bool {
|
||||
if s == nil || other == nil {
|
||||
return s == other
|
||||
}
|
||||
|
||||
// If the versions are different, they're certainly not equal
|
||||
if s.Version != other.Version {
|
||||
return false
|
||||
|
@ -431,7 +480,7 @@ func (s *State) Equal(other *State) bool {
|
|||
}
|
||||
for _, m := range s.Modules {
|
||||
// This isn't very optimal currently but works.
|
||||
otherM := other.ModuleByPath(m.Path)
|
||||
otherM := other.moduleByPath(m.Path)
|
||||
if otherM == nil {
|
||||
return false
|
||||
}
|
||||
|
@ -466,7 +515,6 @@ const (
|
|||
// An error is returned if the two states are not of the same lineage,
|
||||
// in which case the integer returned has no meaning.
|
||||
func (s *State) CompareAges(other *State) (StateAgeComparison, error) {
|
||||
|
||||
// nil states are "older" than actual states
|
||||
switch {
|
||||
case s != nil && other == nil:
|
||||
|
@ -483,6 +531,9 @@ func (s *State) CompareAges(other *State) (StateAgeComparison, error) {
|
|||
)
|
||||
}
|
||||
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
switch {
|
||||
case s.Serial < other.Serial:
|
||||
return StateAgeReceiverOlder, nil
|
||||
|
@ -496,6 +547,9 @@ func (s *State) CompareAges(other *State) (StateAgeComparison, error) {
|
|||
// SameLineage returns true only if the state given in argument belongs
|
||||
// to the same "lineage" of states as the reciever.
|
||||
func (s *State) SameLineage(other *State) bool {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
// If one of the states has no lineage then it is assumed to predate
|
||||
// this concept, and so we'll accept it as belonging to any lineage
|
||||
// so that a lineage string can be assigned to newer versions
|
||||
|
@ -527,10 +581,13 @@ func (s *State) IncrementSerialMaybe(other *State) {
|
|||
if other == nil {
|
||||
return
|
||||
}
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if s.Serial > other.Serial {
|
||||
return
|
||||
}
|
||||
if other.TFVersion != s.TFVersion || !s.Equal(other) {
|
||||
if other.TFVersion != s.TFVersion || !s.equal(other) {
|
||||
if other.Serial > s.Serial {
|
||||
s.Serial = other.Serial
|
||||
}
|
||||
|
@ -542,6 +599,9 @@ func (s *State) IncrementSerialMaybe(other *State) {
|
|||
// FromFutureTerraform checks if this state was written by a Terraform
|
||||
// version from the future.
|
||||
func (s *State) FromFutureTerraform() bool {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
// No TF version means it is certainly from the past
|
||||
if s.TFVersion == "" {
|
||||
return false
|
||||
|
@ -552,6 +612,8 @@ func (s *State) FromFutureTerraform() bool {
|
|||
}
|
||||
|
||||
func (s *State) Init() {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
s.init()
|
||||
}
|
||||
|
||||
|
@ -559,10 +621,10 @@ func (s *State) init() {
|
|||
if s.Version == 0 {
|
||||
s.Version = StateVersion
|
||||
}
|
||||
if s.ModuleByPath(rootModulePath) == nil {
|
||||
s.AddModule(rootModulePath)
|
||||
if s.moduleByPath(rootModulePath) == nil {
|
||||
s.addModule(rootModulePath)
|
||||
}
|
||||
s.EnsureHasLineage()
|
||||
s.ensureHasLineage()
|
||||
|
||||
for _, mod := range s.Modules {
|
||||
mod.init()
|
||||
|
@ -574,6 +636,13 @@ func (s *State) init() {
|
|||
}
|
||||
|
||||
func (s *State) EnsureHasLineage() {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
s.ensureHasLineage()
|
||||
}
|
||||
|
||||
func (s *State) ensureHasLineage() {
|
||||
if s.Lineage == "" {
|
||||
s.Lineage = uuid.NewV4().String()
|
||||
log.Printf("[DEBUG] New state was assigned lineage %q\n", s.Lineage)
|
||||
|
@ -585,7 +654,13 @@ func (s *State) EnsureHasLineage() {
|
|||
// AddModuleState insert this module state and override any existing ModuleState
|
||||
func (s *State) AddModuleState(mod *ModuleState) {
|
||||
mod.init()
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
s.addModuleState(mod)
|
||||
}
|
||||
|
||||
func (s *State) addModuleState(mod *ModuleState) {
|
||||
for i, m := range s.Modules {
|
||||
if reflect.DeepEqual(m.Path, mod.Path) {
|
||||
s.Modules[i] = mod
|
||||
|
@ -624,6 +699,8 @@ func (s *State) String() string {
|
|||
if s == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
var buf bytes.Buffer
|
||||
for _, m := range s.Modules {
|
||||
|
@ -691,10 +768,19 @@ func (r *RemoteState) deepcopy() *RemoteState {
|
|||
}
|
||||
|
||||
func (r *RemoteState) Empty() bool {
|
||||
return r == nil || r.Type == ""
|
||||
if r == nil {
|
||||
return true
|
||||
}
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
return r.Type == ""
|
||||
}
|
||||
|
||||
func (r *RemoteState) Equals(other *RemoteState) bool {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
if r.Type != other.Type {
|
||||
return false
|
||||
}
|
||||
|
@ -741,6 +827,8 @@ func (s *OutputState) Equal(other *OutputState) bool {
|
|||
if s == nil || other == nil {
|
||||
return false
|
||||
}
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if s.Type != other.Type {
|
||||
return false
|
||||
|
@ -811,6 +899,9 @@ func (s *ModuleState) Unlock() { s.mu.Unlock() }
|
|||
|
||||
// Equal tests whether one module state is equal to another.
|
||||
func (m *ModuleState) Equal(other *ModuleState) bool {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
// Paths must be equal
|
||||
if !reflect.DeepEqual(m.Path, other.Path) {
|
||||
return false
|
||||
|
@ -859,11 +950,16 @@ func (m *ModuleState) Equal(other *ModuleState) bool {
|
|||
|
||||
// IsRoot says whether or not this module diff is for the root module.
|
||||
func (m *ModuleState) IsRoot() bool {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
return reflect.DeepEqual(m.Path, rootModulePath)
|
||||
}
|
||||
|
||||
// IsDescendent returns true if other is a descendent of this module.
|
||||
func (m *ModuleState) IsDescendent(other *ModuleState) bool {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
i := len(m.Path)
|
||||
return len(other.Path) > i && reflect.DeepEqual(other.Path[:i], m.Path)
|
||||
}
|
||||
|
@ -872,6 +968,9 @@ func (m *ModuleState) IsDescendent(other *ModuleState) bool {
|
|||
// but aren't present in the configuration itself. Hence, these keys
|
||||
// represent the state of resources that are orphans.
|
||||
func (m *ModuleState) Orphans(c *config.Config) []string {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
keys := make(map[string]struct{})
|
||||
for k, _ := range m.Resources {
|
||||
keys[k] = struct{}{}
|
||||
|
@ -953,6 +1052,9 @@ func (m *ModuleState) deepcopy() *ModuleState {
|
|||
|
||||
// prune is used to remove any resources that are no longer required
|
||||
func (m *ModuleState) prune() {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
for k, v := range m.Resources {
|
||||
v.prune()
|
||||
|
||||
|
@ -975,6 +1077,9 @@ func (m *ModuleState) sort() {
|
|||
}
|
||||
|
||||
func (m *ModuleState) String() string {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
if len(m.Resources) == 0 {
|
||||
|
@ -1230,6 +1335,9 @@ func (s *ResourceState) Unlock() { s.mu.Unlock() }
|
|||
|
||||
// Equal tests whether two ResourceStates are equal.
|
||||
func (s *ResourceState) Equal(other *ResourceState) bool {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if s.Type != other.Type {
|
||||
return false
|
||||
}
|
||||
|
@ -1259,43 +1367,49 @@ func (s *ResourceState) Equal(other *ResourceState) bool {
|
|||
}
|
||||
|
||||
// Taint marks a resource as tainted.
|
||||
func (r *ResourceState) Taint() {
|
||||
if r.Primary != nil {
|
||||
r.Primary.Tainted = true
|
||||
func (s *ResourceState) Taint() {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if s.Primary != nil {
|
||||
s.Primary.Tainted = true
|
||||
}
|
||||
}
|
||||
|
||||
// Untaint unmarks a resource as tainted.
|
||||
func (r *ResourceState) Untaint() {
|
||||
if r.Primary != nil {
|
||||
r.Primary.Tainted = false
|
||||
func (s *ResourceState) Untaint() {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if s.Primary != nil {
|
||||
s.Primary.Tainted = false
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ResourceState) init() {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
func (s *ResourceState) init() {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if r.Primary == nil {
|
||||
r.Primary = &InstanceState{}
|
||||
if s.Primary == nil {
|
||||
s.Primary = &InstanceState{}
|
||||
}
|
||||
r.Primary.init()
|
||||
s.Primary.init()
|
||||
|
||||
if r.Dependencies == nil {
|
||||
r.Dependencies = []string{}
|
||||
if s.Dependencies == nil {
|
||||
s.Dependencies = []string{}
|
||||
}
|
||||
|
||||
if r.Deposed == nil {
|
||||
r.Deposed = make([]*InstanceState, 0)
|
||||
if s.Deposed == nil {
|
||||
s.Deposed = make([]*InstanceState, 0)
|
||||
}
|
||||
|
||||
for _, dep := range r.Deposed {
|
||||
for _, dep := range s.Deposed {
|
||||
dep.init()
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ResourceState) deepcopy() *ResourceState {
|
||||
copy, err := copystructure.Config{Lock: true}.Copy(r)
|
||||
func (s *ResourceState) deepcopy() *ResourceState {
|
||||
copy, err := copystructure.Config{Lock: true}.Copy(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -1304,26 +1418,35 @@ func (r *ResourceState) deepcopy() *ResourceState {
|
|||
}
|
||||
|
||||
// prune is used to remove any instances that are no longer required
|
||||
func (r *ResourceState) prune() {
|
||||
n := len(r.Deposed)
|
||||
func (s *ResourceState) prune() {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
n := len(s.Deposed)
|
||||
for i := 0; i < n; i++ {
|
||||
inst := r.Deposed[i]
|
||||
inst := s.Deposed[i]
|
||||
if inst == nil || inst.ID == "" {
|
||||
copy(r.Deposed[i:], r.Deposed[i+1:])
|
||||
r.Deposed[n-1] = nil
|
||||
copy(s.Deposed[i:], s.Deposed[i+1:])
|
||||
s.Deposed[n-1] = nil
|
||||
n--
|
||||
i--
|
||||
}
|
||||
}
|
||||
|
||||
r.Deposed = r.Deposed[:n]
|
||||
s.Deposed = s.Deposed[:n]
|
||||
}
|
||||
|
||||
func (r *ResourceState) sort() {
|
||||
sort.Strings(r.Dependencies)
|
||||
func (s *ResourceState) sort() {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
sort.Strings(s.Dependencies)
|
||||
}
|
||||
|
||||
func (s *ResourceState) String() string {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString(fmt.Sprintf("Type = %s", s.Type))
|
||||
return buf.String()
|
||||
|
@ -1360,36 +1483,36 @@ type InstanceState struct {
|
|||
func (s *InstanceState) Lock() { s.mu.Lock() }
|
||||
func (s *InstanceState) Unlock() { s.mu.Unlock() }
|
||||
|
||||
func (i *InstanceState) init() {
|
||||
i.Lock()
|
||||
defer i.Unlock()
|
||||
func (s *InstanceState) init() {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if i.Attributes == nil {
|
||||
i.Attributes = make(map[string]string)
|
||||
if s.Attributes == nil {
|
||||
s.Attributes = make(map[string]string)
|
||||
}
|
||||
if i.Meta == nil {
|
||||
i.Meta = make(map[string]string)
|
||||
if s.Meta == nil {
|
||||
s.Meta = make(map[string]string)
|
||||
}
|
||||
i.Ephemeral.init()
|
||||
s.Ephemeral.init()
|
||||
}
|
||||
|
||||
// Copy all the Fields from another InstanceState
|
||||
func (i *InstanceState) Set(from *InstanceState) {
|
||||
i.Lock()
|
||||
defer i.Unlock()
|
||||
func (s *InstanceState) Set(from *InstanceState) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
from.Lock()
|
||||
defer from.Unlock()
|
||||
|
||||
i.ID = from.ID
|
||||
i.Attributes = from.Attributes
|
||||
i.Ephemeral = from.Ephemeral
|
||||
i.Meta = from.Meta
|
||||
i.Tainted = from.Tainted
|
||||
s.ID = from.ID
|
||||
s.Attributes = from.Attributes
|
||||
s.Ephemeral = from.Ephemeral
|
||||
s.Meta = from.Meta
|
||||
s.Tainted = from.Tainted
|
||||
}
|
||||
|
||||
func (i *InstanceState) DeepCopy() *InstanceState {
|
||||
copy, err := copystructure.Config{Lock: true}.Copy(i)
|
||||
func (s *InstanceState) DeepCopy() *InstanceState {
|
||||
copy, err := copystructure.Config{Lock: true}.Copy(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -1398,7 +1521,13 @@ func (i *InstanceState) DeepCopy() *InstanceState {
|
|||
}
|
||||
|
||||
func (s *InstanceState) Empty() bool {
|
||||
return s == nil || s.ID == ""
|
||||
if s == nil {
|
||||
return true
|
||||
}
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
return s.ID == ""
|
||||
}
|
||||
|
||||
func (s *InstanceState) Equal(other *InstanceState) bool {
|
||||
|
@ -1406,6 +1535,8 @@ func (s *InstanceState) Equal(other *InstanceState) bool {
|
|||
if s == nil || other == nil {
|
||||
return s == other
|
||||
}
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
// IDs must be equal
|
||||
if s.ID != other.ID {
|
||||
|
@ -1465,6 +1596,8 @@ func (s *InstanceState) MergeDiff(d *InstanceDiff) *InstanceState {
|
|||
result.init()
|
||||
|
||||
if s != nil {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
for k, v := range s.Attributes {
|
||||
result.Attributes[k] = v
|
||||
}
|
||||
|
@ -1487,16 +1620,19 @@ func (s *InstanceState) MergeDiff(d *InstanceDiff) *InstanceState {
|
|||
return result
|
||||
}
|
||||
|
||||
func (i *InstanceState) String() string {
|
||||
func (s *InstanceState) String() string {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
if i == nil || i.ID == "" {
|
||||
if s == nil || s.ID == "" {
|
||||
return "<not created>"
|
||||
}
|
||||
|
||||
buf.WriteString(fmt.Sprintf("ID = %s\n", i.ID))
|
||||
buf.WriteString(fmt.Sprintf("ID = %s\n", s.ID))
|
||||
|
||||
attributes := i.Attributes
|
||||
attributes := s.Attributes
|
||||
attrKeys := make([]string, 0, len(attributes))
|
||||
for ak, _ := range attributes {
|
||||
if ak == "id" {
|
||||
|
@ -1512,7 +1648,7 @@ func (i *InstanceState) String() string {
|
|||
buf.WriteString(fmt.Sprintf("%s = %s\n", ak, av))
|
||||
}
|
||||
|
||||
buf.WriteString(fmt.Sprintf("Tainted = %t\n", i.Tainted))
|
||||
buf.WriteString(fmt.Sprintf("Tainted = %t\n", s.Tainted))
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue