github.com/opentofu/opentofu@v1.7.1/internal/checks/state_init.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 checks
     7  
     8  import (
     9  	"github.com/opentofu/opentofu/internal/addrs"
    10  	"github.com/opentofu/opentofu/internal/configs"
    11  )
    12  
    13  func initialStatuses(cfg *configs.Config) addrs.Map[addrs.ConfigCheckable, *configCheckableState] {
    14  	ret := addrs.MakeMap[addrs.ConfigCheckable, *configCheckableState]()
    15  	if cfg == nil {
    16  		// This should not happen in normal use, but can arise in some
    17  		// unit tests that are not working with a full configuration and
    18  		// don't care about checks.
    19  		return ret
    20  	}
    21  
    22  	collectInitialStatuses(ret, cfg)
    23  
    24  	return ret
    25  }
    26  
    27  func collectInitialStatuses(into addrs.Map[addrs.ConfigCheckable, *configCheckableState], cfg *configs.Config) {
    28  	moduleAddr := cfg.Path
    29  
    30  	for _, rc := range cfg.Module.ManagedResources {
    31  		addr := rc.Addr().InModule(moduleAddr)
    32  		collectInitialStatusForResource(into, addr, rc)
    33  	}
    34  	for _, rc := range cfg.Module.DataResources {
    35  		addr := rc.Addr().InModule(moduleAddr)
    36  		collectInitialStatusForResource(into, addr, rc)
    37  	}
    38  
    39  	for _, oc := range cfg.Module.Outputs {
    40  		addr := oc.Addr().InModule(moduleAddr)
    41  
    42  		ct := len(oc.Preconditions)
    43  		if ct == 0 {
    44  			// We just ignore output values that don't declare any checks.
    45  			continue
    46  		}
    47  
    48  		st := &configCheckableState{}
    49  
    50  		st.checkTypes = map[addrs.CheckRuleType]int{
    51  			addrs.OutputPrecondition: ct,
    52  		}
    53  
    54  		into.Put(addr, st)
    55  	}
    56  
    57  	for _, c := range cfg.Module.Checks {
    58  		addr := c.Addr().InModule(moduleAddr)
    59  
    60  		st := &configCheckableState{
    61  			checkTypes: map[addrs.CheckRuleType]int{
    62  				addrs.CheckAssertion: len(c.Asserts),
    63  			},
    64  		}
    65  
    66  		if c.DataResource != nil {
    67  			st.checkTypes[addrs.CheckDataResource] = 1
    68  		}
    69  
    70  		into.Put(addr, st)
    71  	}
    72  
    73  	for _, v := range cfg.Module.Variables {
    74  		addr := v.Addr().InModule(moduleAddr)
    75  
    76  		vs := len(v.Validations)
    77  		if vs == 0 {
    78  			continue
    79  		}
    80  
    81  		st := &configCheckableState{}
    82  		st.checkTypes = map[addrs.CheckRuleType]int{
    83  			addrs.InputValidation: vs,
    84  		}
    85  
    86  		into.Put(addr, st)
    87  	}
    88  
    89  	// Must also visit child modules to collect everything
    90  	for _, child := range cfg.Children {
    91  		collectInitialStatuses(into, child)
    92  	}
    93  }
    94  
    95  func collectInitialStatusForResource(into addrs.Map[addrs.ConfigCheckable, *configCheckableState], addr addrs.ConfigResource, rc *configs.Resource) {
    96  	if (len(rc.Preconditions) + len(rc.Postconditions)) == 0 {
    97  		// Don't bother with any resource that doesn't have at least
    98  		// one condition.
    99  		return
   100  	}
   101  
   102  	st := &configCheckableState{
   103  		checkTypes: make(map[addrs.CheckRuleType]int),
   104  	}
   105  
   106  	if ct := len(rc.Preconditions); ct > 0 {
   107  		st.checkTypes[addrs.ResourcePrecondition] = ct
   108  	}
   109  	if ct := len(rc.Postconditions); ct > 0 {
   110  		st.checkTypes[addrs.ResourcePostcondition] = ct
   111  	}
   112  
   113  	into.Put(addr, st)
   114  }