Skip to content

Commit 89cd14e

Browse files
add proposed new protocol
1 parent a5071f9 commit 89cd14e

File tree

4 files changed

+268
-3
lines changed

4 files changed

+268
-3
lines changed

pkg/internal/tests/protocolspec/bridge.go

-3
Original file line numberDiff line numberDiff line change
@@ -160,11 +160,8 @@ func (b *Bridge[CPS, PPS, CTFS, PTFS]) ReadForRefresh(
160160
) (PulumiInput[CPS], PulumiOutput[CPS]) {
161161
tfState := b.tfRawStateFromPulumiOutput(state)
162162
tfUpgradedState := b.TFProvider.UpgradeState(tfState)
163-
164163
tfNewState := b.TFProvider.ReadResource(tfUpgradedState)
165-
166164
newPulumiState := b.tfStateToPulumiOutput(tfNewState)
167-
168165
newPulumiInputs := b.extractInputsFromOutputs(inputs, newPulumiState)
169166
return newPulumiInputs, newPulumiState
170167
}
+140
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package protocolspec
2+
3+
type BridgeV2[CPS PulumiSchema, CTFS TFSchema] struct {
4+
TFProvider TFProvider[CTFS]
5+
}
6+
7+
var _ PulumiProviderV2[PulumiSchema] = &BridgeV2[PulumiSchema, TFSchema]{}
8+
9+
func (b *BridgeV2[CPS, CTFS]) tfStateToPulumiOutput(TFState[CTFS]) PulumiOutput[CPS] {
10+
return PulumiOutput[CPS]{}
11+
}
12+
13+
func (b *BridgeV2[CPS, CTFS]) tfPlannedStateToPulumiPreviewOutput(
14+
TFPlannedState[CTFS],
15+
) PulumiPreviewOutput[CPS] {
16+
return PulumiPreviewOutput[CPS]{}
17+
}
18+
19+
// This is new.
20+
func (b *BridgeV2[CPS, CTFS]) pulumiPreviewOutputToTFPlannedState(PulumiPreviewOutput[CPS]) TFPlannedState[CTFS] {
21+
return TFPlannedState[CTFS]{}
22+
}
23+
24+
func (b *BridgeV2[CPS, CTFS]) pulumiInputToTFConfig(PulumiInput[CPS]) TFConfig[CTFS] {
25+
return TFConfig[CTFS]{}
26+
}
27+
28+
func (b *BridgeV2[CPS, CTFS]) tfRawStateFromPulumiOutput(PulumiOutput[CPS]) TFState[CTFS] {
29+
return TFState[CTFS]{}
30+
}
31+
32+
func (b *BridgeV2[CPS, CTFS]) Check(news PulumiInput[CPS]) PulumiInput[CPS] {
33+
return PulumiInput[CPS]{}
34+
}
35+
36+
func (b *BridgeV2[CPS, CTFS]) CreatePreview(inputs PulumiInput[CPS]) PulumiPreviewOutput[CPS] {
37+
tfConfig := b.pulumiInputToTFConfig(inputs)
38+
emptyState := TFState[CTFS]{}
39+
tfPlannedState := b.TFProvider.PlanResourceChange(tfConfig, emptyState)
40+
return b.tfPlannedStateToPulumiPreviewOutput(tfPlannedState)
41+
}
42+
43+
func (b *BridgeV2[CPS, CTFS]) Create(inputs PulumiInput[CPS]) PulumiOutput[CPS] {
44+
tfConfig := b.pulumiInputToTFConfig(inputs)
45+
emptyState := TFState[CTFS]{}
46+
tfPlannedState := b.TFProvider.PlanResourceChange(tfConfig, emptyState)
47+
tfState := b.TFProvider.ApplyResourceChange(tfConfig, emptyState, tfPlannedState)
48+
return b.tfStateToPulumiOutput(tfState)
49+
}
50+
51+
func (b *BridgeV2[CPS, CTFS]) UpdatePreview(inputs PulumiInput[CPS], state PulumiOutput[CPS]) PulumiPreviewOutput[CPS] {
52+
tfConfig := b.pulumiInputToTFConfig(inputs)
53+
tfState := b.tfRawStateFromPulumiOutput(state)
54+
tfPlannedState := b.TFProvider.PlanResourceChange(tfConfig, tfState)
55+
return b.tfPlannedStateToPulumiPreviewOutput(tfPlannedState)
56+
}
57+
58+
func (b *BridgeV2[CPS, CTFS]) Update(inputs PulumiInput[CPS], state PulumiOutput[CPS]) PulumiOutput[CPS] {
59+
tfConfig := b.pulumiInputToTFConfig(inputs)
60+
tfState := b.tfRawStateFromPulumiOutput(state)
61+
tfPlannedState := b.TFProvider.PlanResourceChange(tfConfig, tfState)
62+
tfState = b.TFProvider.ApplyResourceChange(tfConfig, tfState, tfPlannedState)
63+
return b.tfStateToPulumiOutput(tfState)
64+
}
65+
66+
func (b *BridgeV2[CPS, CTFS]) DeletePreview(state PulumiOutput[CPS]) PulumiPreviewOutput[CPS] {
67+
tfConfig := TFConfig[CTFS]{}
68+
tfState := b.tfRawStateFromPulumiOutput(state)
69+
tfPlannedState := b.TFProvider.PlanResourceChange(tfConfig, tfState)
70+
return b.tfPlannedStateToPulumiPreviewOutput(tfPlannedState)
71+
}
72+
73+
func (b *BridgeV2[CPS, CTFS]) Delete(state PulumiOutput[CPS]) PulumiOutput[CPS] {
74+
tfConfig := TFConfig[CTFS]{}
75+
tfState := b.tfRawStateFromPulumiOutput(state)
76+
tfPlannedState := b.TFProvider.PlanResourceChange(tfConfig, tfState)
77+
tfState = b.TFProvider.ApplyResourceChange(tfConfig, tfState, tfPlannedState)
78+
return b.tfStateToPulumiOutput(tfState)
79+
}
80+
81+
func (b *BridgeV2[CPS, CTFS]) Diff(oldState PulumiOutput[CPS], plannedState PulumiPreviewOutput[CPS]) (PulumiDiff[CPS], PulumiDetailedDiffV2[CPS]) {
82+
tfState := b.tfRawStateFromPulumiOutput(oldState)
83+
tfPlannedState := b.pulumiPreviewOutputToTFPlannedState(plannedState)
84+
tfDiff := b.TFProvider.Diff(tfState, tfPlannedState)
85+
86+
translateTFDiffToPulumiDiff := func(TFDiff[CTFS]) PulumiDiff[CPS] {
87+
return PulumiDiff[CPS]{}
88+
}
89+
90+
producePulumiDetailedDiff := func(
91+
oldState PulumiOutput[CPS],
92+
plannedState PulumiPreviewOutput[CPS],
93+
) PulumiDetailedDiffV2[CPS] {
94+
// The values here are in the same plane - much easier to produce a diff.
95+
return PulumiDetailedDiffV2[CPS]{
96+
OldState: oldState,
97+
plannedState: plannedState,
98+
}
99+
}
100+
101+
pulumiDiff := translateTFDiffToPulumiDiff(tfDiff)
102+
pulumiDetailedDiff := producePulumiDetailedDiff(oldState, plannedState)
103+
104+
return pulumiDiff, pulumiDetailedDiff
105+
}
106+
107+
// extractInputsFromOutputs is not precise and has some assumptions and approximations
108+
// Especially when there are no past inputs
109+
func (b *BridgeV2[CPS, CTFS]) extractInputsFromOutputsNoInputs(
110+
outputs PulumiOutput[CPS],
111+
) PulumiInput[CPS] {
112+
// guess
113+
return PulumiInput[CPS]{}
114+
}
115+
116+
func (b *BridgeV2[CPS, CTFS]) ReadForImport(id string) (PulumiOutput[CPS], PulumiInput[CPS]) {
117+
tfState := b.TFProvider.Importer(id)
118+
state := b.tfStateToPulumiOutput(tfState)
119+
inputs := b.extractInputsFromOutputsNoInputs(state)
120+
return state, inputs
121+
}
122+
123+
func (b *BridgeV2[CPS, CTFS]) ReadForRefresh(state PulumiOutput[CPS]) (PulumiOutput[CPS]) {
124+
tfState := b.tfRawStateFromPulumiOutput(state)
125+
tfNewState := b.TFProvider.ReadResource(tfState)
126+
newState := b.tfStateToPulumiOutput(tfNewState)
127+
return newState
128+
}
129+
130+
// The only method which needs to deal with old schema is UpgradeState.
131+
type BridgeV2WithUpgrade[CPS PulumiSchema, PS PulumiSchema, CTFS TFSchema, PTS TFSchema] struct {
132+
BridgeV2[CPS, CTFS]
133+
TFProvider TFProviderWithUpgradeState[CTFS, PTS]
134+
}
135+
136+
var _ PulumiProviderV2WithUpgrade[PulumiSchema, PulumiSchema] = &BridgeV2WithUpgrade[PulumiSchema, PulumiSchema, TFSchema, TFSchema]{}
137+
138+
func (b *BridgeV2WithUpgrade[CPS, PS, CTFS, PTS]) UpgradeState(state PulumiOutput[PS]) PulumiOutput[CPS] {
139+
return PulumiOutput[CPS]{}
140+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package protocolspec
2+
3+
func getOldInputsV2[S PulumiSchema]() PulumiInput[S] {
4+
return PulumiInput[S]{}
5+
}
6+
7+
func CreateResourceV2() {
8+
type PS struct{}
9+
type TFS struct{}
10+
prov := &BridgeV2[PS, TFS]{}
11+
userInputs := getUserInputs[PS]()
12+
13+
checkedInputs := prov.Check(userInputs)
14+
previewOutputs := prov.CreatePreview(checkedInputs)
15+
16+
displayPreviewV2(previewOutputs, PulumiOutput[PS]{}, PulumiDetailedDiffV2[PS]{})
17+
}
18+
19+
20+
func UpdateResourceWithUpgradeV2() {
21+
type CPS struct{}
22+
type CTFS struct{}
23+
type PPS struct{}
24+
type PTFS struct{}
25+
prov := &BridgeV2WithUpgrade[CPS, PPS, CTFS, PTFS]{}
26+
userInputs := getUserInputs[CPS]()
27+
oldState := getOldState[PPS]()
28+
// oldInputs := getOldInputs[PPS]() not used anymore
29+
30+
checkedInputs := prov.Check(userInputs)
31+
upgradedState := prov.UpgradeState(oldState)
32+
33+
proposedState := prov.UpdatePreview(checkedInputs, upgradedState)
34+
35+
diff, detailedDiff := prov.Diff(upgradedState, proposedState)
36+
37+
displayPreviewV2(proposedState, upgradedState, detailedDiff)
38+
39+
if diff.HasChanges {
40+
prov.Update(checkedInputs, upgradedState)
41+
}
42+
}
43+
44+
// Assumes run-program
45+
func DeleteResourceWithUpgradeV2() {
46+
type CPS struct{}
47+
type CTFS struct{}
48+
type PPS struct{}
49+
type PTFS struct{}
50+
51+
prov := &BridgeV2WithUpgrade[CPS, PPS, CTFS, PTFS]{}
52+
oldState := getOldState[PPS]()
53+
upgradedState := prov.UpgradeState(oldState)
54+
55+
prov.Delete(upgradedState)
56+
}
57+
58+
func RefreshWithUpgradeV2() {
59+
type CPS struct{}
60+
type CTFS struct{}
61+
type PPS struct{}
62+
type PTFS struct{}
63+
64+
prov := &BridgeV2WithUpgrade[CPS, PPS, CTFS, PTFS]{}
65+
state := getOldState[PPS]()
66+
67+
upgradedState := prov.UpgradeState(state)
68+
readState := prov.ReadForRefresh(upgradedState)
69+
70+
promoteToPreviewOutput := func(state PulumiOutput[CPS]) PulumiPreviewOutput[CPS] {
71+
return PulumiPreviewOutput[CPS]{}
72+
}
73+
74+
promotedUpgradedState := promoteToPreviewOutput(upgradedState)
75+
76+
//nolint:lll
77+
// parameter inversion here: https://pulumi-developer-docs.readthedocs.io/latest/developer-docs/providers/implementers-guide.html#refresh
78+
diff, detailedDiff := prov.Diff(
79+
readState,
80+
promotedUpgradedState,
81+
)
82+
83+
displayPreviewV2(promotedUpgradedState, readState, detailedDiff)
84+
if diff.HasChanges {
85+
// save the state
86+
}
87+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package protocolspec
2+
3+
type PulumiDetailedDiffV2[CS PulumiSchema] struct {
4+
OldState PulumiOutput[CS]
5+
plannedState PulumiPreviewOutput[CS]
6+
}
7+
8+
// Note that the only provider method that needs to deal with old schema is UpgradeState.
9+
// Note also that old inputs are not needed for any method.
10+
type PulumiProviderV2[CS PulumiSchema] interface {
11+
// Check shouldn't apply defaults, so old Inputs are not needed. Checked input then becomes the same as input but validated.
12+
Check(news PulumiInput[CS]) PulumiInput[CS]
13+
14+
CreatePreview(inputs PulumiInput[CS]) PulumiPreviewOutput[CS]
15+
// Should we go further here and avoid replanning? What is needed to achieve this?
16+
Create(inputs PulumiInput[CS]) PulumiOutput[CS]
17+
18+
// Old inputs are not needed for Update and are currently unused.
19+
UpdatePreview(inputs PulumiInput[CS], upgradedState PulumiOutput[CS]) PulumiPreviewOutput[CS]
20+
// Avoid replanning?
21+
Update(inputs PulumiInput[CS], upgradedState PulumiOutput[CS]) PulumiOutput[CS]
22+
23+
DeletePreview(upgradedState PulumiOutput[CS]) PulumiPreviewOutput[CS]
24+
// Avoid replanning?
25+
Delete(upgradedState PulumiOutput[CS]) PulumiOutput[CS]
26+
27+
Diff(oldUpgradedState PulumiOutput[CS], plannedState PulumiPreviewOutput[CS]) (PulumiDiff[CS], PulumiDetailedDiffV2[CS])
28+
29+
ReadForImport(id string) (PulumiOutput[CS], PulumiInput[CS])
30+
ReadForRefresh(state PulumiOutput[CS]) (PulumiOutput[CS])
31+
}
32+
33+
type PulumiProviderV2WithUpgrade[CS PulumiSchema, PS PulumiSchema] interface {
34+
PulumiProviderV2[CS]
35+
UpgradeState(state PulumiOutput[PS]) PulumiOutput[CS]
36+
}
37+
38+
func displayPreviewV2[CS PulumiSchema](
39+
proposedState PulumiPreviewOutput[CS], upgradedOldState PulumiOutput[CS], dd PulumiDetailedDiffV2[CS],
40+
) {
41+
}

0 commit comments

Comments
 (0)