8 // StateFilter is responsible for filtering and searching a state.
10 // This is a separate struct from State rather than a method on State
11 // because StateFilter might create sidecar data structures to optimize
12 // filtering on the state.
14 // If you change the State, the filter created is invalid and either
15 // Reset should be called or a new one should be allocated. StateFilter
16 // will not watch State for changes and do this for you. If you filter after
17 // changing the State without calling Reset, the behavior is not defined.
18 type StateFilter struct {
22 // Filter takes the addresses specified by fs and finds all the matches.
23 // The values of fs are resource addressing syntax that can be parsed by
24 // ParseResourceAddress.
25 func (f *StateFilter) Filter(fs ...string) ([]*StateFilterResult, error) {
26 // Parse all the addresses
27 as := make([]*ResourceAddress, len(fs))
28 for i, v := range fs {
29 a, err := ParseResourceAddress(v)
31 return nil, fmt.Errorf("Error parsing address '%s': %s", v, err)
37 // If we weren't given any filters, then we list all
39 as = append(as, &ResourceAddress{Index: -1})
42 // Filter each of the address. We keep track of this in a map to
44 resultSet := make(map[string]*StateFilterResult)
45 for _, a := range as {
46 for _, r := range f.filterSingle(a) {
47 resultSet[r.String()] = r
51 // Make the result list
52 results := make([]*StateFilterResult, 0, len(resultSet))
53 for _, v := range resultSet {
54 results = append(results, v)
57 // Sort them and return
58 sort.Sort(StateFilterResultSlice(results))
62 func (f *StateFilter) filterSingle(a *ResourceAddress) []*StateFilterResult {
63 // The slice to keep track of results
64 var results []*StateFilterResult
66 // Go through modules first.
67 modules := make([]*ModuleState, 0, len(f.State.Modules))
68 for _, m := range f.State.Modules {
70 modules = append(modules, m)
72 // Only add the module to the results if we haven't specified a type.
73 // We also ignore the root module.
74 if a.Type == "" && len(m.Path) > 1 {
75 results = append(results, &StateFilterResult{
77 Address: (&ResourceAddress{Path: m.Path[1:]}).String(),
84 // With the modules set, go through all the resources within
85 // the modules to find relevant resources.
86 for _, m := range modules {
87 for n, r := range m.Resources {
88 // The name in the state contains valuable information. Parse.
89 key, err := ParseResourceStateKey(n)
91 // If we get an error parsing, then just ignore it
96 // Older states and test fixtures often don't contain the
97 // type directly on the ResourceState. We add this so StateFilter
98 // is a bit more robust.
103 if f.relevant(a, r) {
104 if a.Name != "" && a.Name != key.Name {
105 // Name doesn't match
109 if a.Index >= 0 && key.Index != a.Index {
110 // Index doesn't match
114 if a.Name != "" && a.Name != key.Name {
118 // Build the address for this resource
119 addr := &ResourceAddress{
126 // Add the resource level result
127 resourceResult := &StateFilterResult{
129 Address: addr.String(),
132 if !a.InstanceTypeSet {
133 results = append(results, resourceResult)
137 if r.Primary != nil {
138 addr.InstanceType = TypePrimary
139 addr.InstanceTypeSet = false
140 results = append(results, &StateFilterResult{
142 Address: addr.String(),
143 Parent: resourceResult,
148 for _, instance := range r.Deposed {
149 if f.relevant(a, instance) {
150 addr.InstanceType = TypeDeposed
151 addr.InstanceTypeSet = true
152 results = append(results, &StateFilterResult{
154 Address: addr.String(),
155 Parent: resourceResult,
167 // relevant checks for relevance of this address against the given value.
168 func (f *StateFilter) relevant(addr *ResourceAddress, raw interface{}) bool {
169 switch v := raw.(type) {
173 if len(addr.Path) > len(path) {
174 // Longer path in address means there is no way we match.
178 // Check for a prefix match
179 for i, p := range addr.Path {
181 // Any mismatches don't match.
189 // If we have no resource type, then we're interested in all!
193 // If the type doesn't match we fail immediately
194 if v.Type != addr.Type {
200 // If we don't know about it, let's just say no
205 // StateFilterResult is a single result from a filter operation. Filter
206 // can match multiple things within a state (module, resource, instance, etc.)
207 // and this unifies that.
208 type StateFilterResult struct {
209 // Module path of the result
212 // Address is the address that can be used to reference this exact result.
215 // Parent, if non-nil, is a parent of this result. For instances, the
216 // parent would be a resource. For resources, the parent would be
217 // a module. For modules, this is currently nil.
218 Parent *StateFilterResult
220 // Value is the actual value. This must be type switched on. It can be
221 // any data structures that `State` can hold: `ModuleState`,
222 // `ResourceState`, `InstanceState`.
226 func (r *StateFilterResult) String() string {
227 return fmt.Sprintf("%T: %s", r.Value, r.Address)
230 func (r *StateFilterResult) sortedType() int {
231 switch r.Value.(type) {
243 // StateFilterResultSlice is a slice of results that implements
244 // sort.Interface. The sorting goal is what is most appealing to
246 type StateFilterResultSlice []*StateFilterResult
248 func (s StateFilterResultSlice) Len() int { return len(s) }
249 func (s StateFilterResultSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
250 func (s StateFilterResultSlice) Less(i, j int) bool {
253 // if these address contain an index, we want to sort by index rather than name
254 addrA, errA := ParseResourceAddress(a.Address)
255 addrB, errB := ParseResourceAddress(b.Address)
256 if errA == nil && errB == nil && addrA.Name == addrB.Name && addrA.Index != addrB.Index {
257 return addrA.Index < addrB.Index
260 // If the addresses are different it is just lexographic sorting
261 if a.Address != b.Address {
262 return a.Address < b.Address
265 // Addresses are the same, which means it matters on the type
266 return a.sortedType() < b.sortedType()