Skip to content

Commit be242c3

Browse files
authored
Stacks migrate: migration workflow improvements (#36882)
1 parent c161997 commit be242c3

File tree

7 files changed

+346
-61
lines changed

7 files changed

+346
-61
lines changed

internal/stacks/stackmigrate/migrate_test.go

Lines changed: 237 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -526,52 +526,57 @@ func TestMigrateConfig_NestedModuleResources(t *testing.T) {
526526
mustDefaultRootProvider("testing"),
527527
)
528528

529-
childModule := state.EnsureModule(addrs.RootModuleInstance.Child("child_mod", addrs.NoKey))
530-
childModule.SetResourceInstanceCurrent(
531-
addrs.Resource{
532-
Mode: addrs.ManagedResourceMode,
533-
Type: "testing_resource",
534-
Name: "child_data",
535-
}.Instance(addrs.NoKey),
536-
&states.ResourceInstanceObjectSrc{
537-
Status: states.ObjectReady,
538-
AttrsJSON: []byte(`{
529+
children := []*states.Module{
530+
state.EnsureModule(addrs.RootModuleInstance.Child("child_mod", addrs.NoKey)),
531+
state.EnsureModule(addrs.RootModuleInstance.Child("child_mod2", addrs.NoKey)),
532+
}
533+
for _, childModule := range children {
534+
childModule.SetResourceInstanceCurrent(
535+
addrs.Resource{
536+
Mode: addrs.ManagedResourceMode,
537+
Type: "testing_resource",
538+
Name: "child_data",
539+
}.Instance(addrs.NoKey),
540+
&states.ResourceInstanceObjectSrc{
541+
Status: states.ObjectReady,
542+
AttrsJSON: []byte(`{
539543
"id": "foo",
540544
"value": "hello"
541545
}`),
542-
},
543-
mustDefaultRootProvider("testing"),
544-
)
545-
childModule.SetResourceInstanceCurrent(
546-
addrs.Resource{
547-
Mode: addrs.ManagedResourceMode,
548-
Type: "testing_resource",
549-
Name: "another_child_data",
550-
}.Instance(addrs.IntKey(0)),
551-
&states.ResourceInstanceObjectSrc{
552-
Status: states.ObjectReady,
553-
AttrsJSON: []byte(`{
546+
},
547+
mustDefaultRootProvider("testing"),
548+
)
549+
childModule.SetResourceInstanceCurrent(
550+
addrs.Resource{
551+
Mode: addrs.ManagedResourceMode,
552+
Type: "testing_resource",
553+
Name: "another_child_data",
554+
}.Instance(addrs.IntKey(0)),
555+
&states.ResourceInstanceObjectSrc{
556+
Status: states.ObjectReady,
557+
AttrsJSON: []byte(`{
554558
"id": "foo",
555559
"value": "hello"
556560
}`),
557-
},
558-
mustDefaultRootProvider("testing"),
559-
)
560-
childModule.SetResourceInstanceCurrent(
561-
addrs.Resource{
562-
Mode: addrs.ManagedResourceMode,
563-
Type: "testing_resource",
564-
Name: "another_child_data",
565-
}.Instance(addrs.IntKey(1)),
566-
&states.ResourceInstanceObjectSrc{
567-
Status: states.ObjectReady,
568-
AttrsJSON: []byte(`{
561+
},
562+
mustDefaultRootProvider("testing"),
563+
)
564+
childModule.SetResourceInstanceCurrent(
565+
addrs.Resource{
566+
Mode: addrs.ManagedResourceMode,
567+
Type: "testing_resource",
568+
Name: "another_child_data",
569+
}.Instance(addrs.IntKey(1)),
570+
&states.ResourceInstanceObjectSrc{
571+
Status: states.ObjectReady,
572+
AttrsJSON: []byte(`{
569573
"id": "foo",
570574
"value": "hello"
571575
}`),
572-
},
573-
mustDefaultRootProvider("testing"),
574-
)
576+
},
577+
mustDefaultRootProvider("testing"),
578+
)
579+
}
575580

576581
mig := Migration{
577582
Providers: map[addrs.Provider]providers.Factory{
@@ -587,7 +592,8 @@ func TestMigrateConfig_NestedModuleResources(t *testing.T) {
587592
"testing_resource.another": "parent",
588593
}
589594
modules := map[string]string{
590-
"child_mod": "child",
595+
"child_mod": "child",
596+
"child_mod2": "child2",
591597
}
592598

593599
appliedResources := []*stackstate.AppliedChangeResourceInstanceObject{}
@@ -671,6 +677,45 @@ func TestMigrateConfig_NestedModuleResources(t *testing.T) {
671677
ProviderConfigAddr: mustDefaultRootProvider("testing"),
672678
Schema: stacks_testing_provider.TestingResourceSchema,
673679
},
680+
{
681+
ResourceInstanceObjectAddr: mustAbsResourceInstanceObject("component.child2.testing_resource.child_data"),
682+
NewStateSrc: &states.ResourceInstanceObjectSrc{
683+
AttrsJSON: mustMarshalJSONAttrs(map[string]interface{}{
684+
"id": "foo",
685+
"value": "hello",
686+
}),
687+
Status: states.ObjectReady,
688+
Private: nil,
689+
},
690+
ProviderConfigAddr: mustDefaultRootProvider("testing"),
691+
Schema: stacks_testing_provider.TestingResourceSchema,
692+
},
693+
{
694+
ResourceInstanceObjectAddr: mustAbsResourceInstanceObject("component.child2.testing_resource.another_child_data[0]"),
695+
NewStateSrc: &states.ResourceInstanceObjectSrc{
696+
AttrsJSON: mustMarshalJSONAttrs(map[string]interface{}{
697+
"id": "foo",
698+
"value": "hello",
699+
}),
700+
Status: states.ObjectReady,
701+
Private: nil,
702+
},
703+
ProviderConfigAddr: mustDefaultRootProvider("testing"),
704+
Schema: stacks_testing_provider.TestingResourceSchema,
705+
},
706+
{
707+
ResourceInstanceObjectAddr: mustAbsResourceInstanceObject("component.child2.testing_resource.another_child_data[1]"),
708+
NewStateSrc: &states.ResourceInstanceObjectSrc{
709+
AttrsJSON: mustMarshalJSONAttrs(map[string]interface{}{
710+
"id": "foo",
711+
"value": "hello",
712+
}),
713+
Status: states.ObjectReady,
714+
Private: nil,
715+
},
716+
ProviderConfigAddr: mustDefaultRootProvider("testing"),
717+
Schema: stacks_testing_provider.TestingResourceSchema,
718+
},
674719
}
675720
expectedComponents := []*stackstate.AppliedChangeComponentInstance{
676721
{
@@ -683,7 +728,7 @@ func TestMigrateConfig_NestedModuleResources(t *testing.T) {
683728
{Name: "id"}: cty.DynamicVal,
684729
{Name: "input"}: cty.DynamicVal,
685730
},
686-
Dependents: collections.NewSet(mustAbsComponent("component.child")),
731+
Dependents: collections.NewSet(mustAbsComponent("component.child"), mustAbsComponent("component.child2")),
687732
},
688733
{
689734
ComponentAddr: mustAbsComponent("component.child"),
@@ -697,6 +742,18 @@ func TestMigrateConfig_NestedModuleResources(t *testing.T) {
697742
},
698743
Dependencies: collections.NewSet(mustAbsComponent("component.parent")),
699744
},
745+
{
746+
ComponentAddr: mustAbsComponent("component.child2"),
747+
ComponentInstanceAddr: mustAbsComponentInstance("component.child2"),
748+
OutputValues: map[addrs.OutputValue]cty.Value{
749+
{Name: "id"}: cty.DynamicVal,
750+
},
751+
InputVariables: map[addrs.InputVariable]cty.Value{
752+
{Name: "id"}: cty.DynamicVal,
753+
{Name: "input"}: cty.DynamicVal,
754+
},
755+
Dependencies: collections.NewSet(mustAbsComponent("component.parent")),
756+
},
700757
}
701758

702759
var expDiags, gotDiags tfdiags.Diagnostics
@@ -1711,3 +1768,144 @@ func reportDiagnosticsForTest(t *testing.T, diags tfdiags.Diagnostics) {
17111768
t.FailNow()
17121769
}
17131770
}
1771+
1772+
func TestMigrateConfig_ChildModuleAsComponentSource(t *testing.T) {
1773+
cfg := loadMainBundleConfigForTest(t, filepath.Join("for-stacks-migrate", "child-module-as-component-source"))
1774+
1775+
lock := depsfile.NewLocks()
1776+
lock.SetProvider(
1777+
addrs.NewDefaultProvider("testing"),
1778+
providerreqs.MustParseVersion("0.0.0"),
1779+
providerreqs.MustParseVersionConstraints("=0.0.0"),
1780+
providerreqs.PreferredHashes([]providerreqs.Hash{}),
1781+
)
1782+
state := states.BuildState(func(ss *states.SyncState) {})
1783+
rootModule := state.RootModule()
1784+
rootModule.SetResourceInstanceCurrent(
1785+
addrs.Resource{
1786+
Mode: addrs.ManagedResourceMode,
1787+
Type: "testing_resource",
1788+
Name: "root_id",
1789+
}.Instance(addrs.NoKey),
1790+
&states.ResourceInstanceObjectSrc{
1791+
Status: states.ObjectReady,
1792+
AttrsJSON: []byte(`{
1793+
"id": "root_id",
1794+
"value": "root_output"
1795+
}`),
1796+
},
1797+
mustDefaultRootProvider("testing"),
1798+
)
1799+
1800+
childModule := state.EnsureModule(addrs.RootModuleInstance.Child("child_module", addrs.NoKey))
1801+
childProv := mustDefaultRootProvider("testing")
1802+
childProv.Module = childModule.Addr.Module()
1803+
childModule.SetResourceInstanceCurrent(
1804+
addrs.Resource{
1805+
Mode: addrs.ManagedResourceMode,
1806+
Type: "testing_resource",
1807+
Name: "child_data",
1808+
}.Instance(addrs.NoKey),
1809+
&states.ResourceInstanceObjectSrc{
1810+
Status: states.ObjectReady,
1811+
AttrsJSON: []byte(`{
1812+
"id": "child_data",
1813+
"value": "child_output"
1814+
}`),
1815+
},
1816+
childProv,
1817+
)
1818+
1819+
mig := Migration{
1820+
Providers: map[addrs.Provider]providers.Factory{
1821+
addrs.NewDefaultProvider("testing"): func() (providers.Interface, error) {
1822+
return stacks_testing_provider.NewProvider(t), nil
1823+
},
1824+
},
1825+
PreviousState: state,
1826+
Config: cfg,
1827+
}
1828+
1829+
resources := map[string]string{
1830+
"testing_resource.root_id": "self",
1831+
"testing_resource.child_data": "self",
1832+
}
1833+
modules := map[string]string{
1834+
"child_module": "triage",
1835+
}
1836+
1837+
appliedResources := []*stackstate.AppliedChangeResourceInstanceObject{}
1838+
appliedComponents := []*stackstate.AppliedChangeComponentInstance{}
1839+
expectedResources := []*stackstate.AppliedChangeResourceInstanceObject{
1840+
{
1841+
ResourceInstanceObjectAddr: mustAbsResourceInstanceObject("component.self.testing_resource.root_id"),
1842+
NewStateSrc: &states.ResourceInstanceObjectSrc{
1843+
AttrsJSON: mustMarshalJSONAttrs(map[string]interface{}{
1844+
"id": "root_id",
1845+
"value": "root_output",
1846+
}),
1847+
Status: states.ObjectReady,
1848+
Private: nil,
1849+
},
1850+
ProviderConfigAddr: mustDefaultRootProvider("testing"),
1851+
Schema: stacks_testing_provider.TestingResourceSchema,
1852+
},
1853+
{
1854+
ResourceInstanceObjectAddr: mustAbsResourceInstanceObject("component.triage.testing_resource.child_data"),
1855+
NewStateSrc: &states.ResourceInstanceObjectSrc{
1856+
AttrsJSON: mustMarshalJSONAttrs(map[string]interface{}{
1857+
"id": "child_data",
1858+
"value": "child_output",
1859+
}),
1860+
Status: states.ObjectReady,
1861+
Private: nil,
1862+
},
1863+
ProviderConfigAddr: mustDefaultRootProvider("testing"),
1864+
Schema: stacks_testing_provider.TestingResourceSchema,
1865+
},
1866+
}
1867+
expectedComponents := []*stackstate.AppliedChangeComponentInstance{
1868+
{
1869+
ComponentAddr: mustAbsComponent("component.self"),
1870+
ComponentInstanceAddr: mustAbsComponentInstance("component.self"),
1871+
OutputValues: map[addrs.OutputValue]cty.Value{},
1872+
InputVariables: map[addrs.InputVariable]cty.Value{},
1873+
},
1874+
{
1875+
ComponentAddr: mustAbsComponent("component.triage"),
1876+
ComponentInstanceAddr: mustAbsComponentInstance("component.triage"),
1877+
OutputValues: map[addrs.OutputValue]cty.Value{},
1878+
InputVariables: map[addrs.InputVariable]cty.Value{
1879+
addrs.InputVariable{Name: "input"}: cty.DynamicVal,
1880+
},
1881+
},
1882+
}
1883+
1884+
var expDiags, gotDiags tfdiags.Diagnostics
1885+
mig.Migrate(resources, modules, func(change stackstate.AppliedChange) {
1886+
switch c := change.(type) {
1887+
case *stackstate.AppliedChangeResourceInstanceObject:
1888+
appliedResources = append(appliedResources, c)
1889+
case *stackstate.AppliedChangeComponentInstance:
1890+
appliedComponents = append(appliedComponents, c)
1891+
}
1892+
}, func(diagnostic tfdiags.Diagnostic) {
1893+
gotDiags = append(gotDiags, diagnostic)
1894+
})
1895+
1896+
if diff := compareAppliedChanges(t, expectedResources, appliedResources, func(c *stackstate.AppliedChangeResourceInstanceObject) string {
1897+
return c.ResourceInstanceObjectAddr.String()
1898+
}); diff != "" {
1899+
t.Errorf("unexpected applied resource changes:\n%s", diff)
1900+
}
1901+
1902+
if diff := compareAppliedChanges(t, expectedComponents, appliedComponents, func(c *stackstate.AppliedChangeComponentInstance) string {
1903+
return c.ComponentAddr.String()
1904+
}); diff != "" {
1905+
t.Errorf("unexpected applied component changes:\n%s", diff)
1906+
}
1907+
1908+
if diff := cmp.Diff(expDiags, gotDiags); diff != "" {
1909+
t.Errorf("unexpected diagnostics:\n%s", diff)
1910+
}
1911+
}

0 commit comments

Comments
 (0)