Skip to content

Commit 4dc08bb

Browse files
protocol spec
1 parent 31a6c1e commit 4dc08bb

File tree

5 files changed

+594
-0
lines changed

5 files changed

+594
-0
lines changed
+170
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
package protocolspec
2+
3+
// CPS stands for Current Pulumi Schema
4+
// PPS stands for Previous Pulumi Schema
5+
// CTFS stands for Current TF Schema
6+
// PTFS stands for Previous TF Schema
7+
type Bridge[CPS PulumiSchema, PPS PulumiSchema, CTFS TFSchema, PTFS TFSchema] struct {
8+
TFProvider TFProviderWithUpgradeState[CTFS, PTFS]
9+
}
10+
11+
func (b *Bridge[CPS, PPS, CTFS, PTFS]) getCurrentBridge() Bridge[CPS, CPS, CTFS, CTFS] {
12+
return Bridge[CPS, CPS, CTFS, CTFS]{
13+
TFProvider: b.TFProvider.GetCurrentProvider(),
14+
}
15+
}
16+
17+
func (b *Bridge[CPS, PPS, CTFS, PTFS]) tfStateToPulumiOutput(TFState[CTFS]) PulumiOutput[CPS] {
18+
return PulumiOutput[CPS]{}
19+
}
20+
21+
func (b *Bridge[CPS, PPS, CTFS, PTFS]) tfPlannedStateToPulumiPreviewOutput(
22+
TFPlannedState[CTFS],
23+
) PulumiPreviewOutput[CPS] {
24+
return PulumiPreviewOutput[CPS]{}
25+
}
26+
27+
// This was recently replaced by tfRawStateFromPulumiOutput
28+
func (b *Bridge[CPS, PPS, CTFS, PTFS]) pulumiOutputToTFState(PulumiOutput[CPS]) TFState[CTFS] {
29+
return TFState[CTFS]{}
30+
}
31+
32+
func (b *Bridge[CPS, PPS, CTFS, PTFS]) pulumiCheckedInputToTFConfig(PulumiCheckedInput[CPS]) TFConfig[CTFS] {
33+
return TFConfig[CTFS]{}
34+
}
35+
36+
func (b *Bridge[CPS, PPS, CTFS, PTFS]) tfRawStateFromPulumiOutput(PulumiOutput[PPS]) TFState[PTFS] {
37+
return TFState[PTFS]{}
38+
}
39+
40+
// extractInputsFromOutputs is not precise and has some assumptions and approximations
41+
// Especially when there are no past inputs
42+
func (b *Bridge[CPS, PPS, CTFS, PTFS]) extractInputsFromOutputs(
43+
oldInputs PulumiCheckedInput[PPS],
44+
outputs PulumiOutput[CPS],
45+
) PulumiInput[CPS] {
46+
return PulumiInput[CPS]{}
47+
}
48+
49+
var _ PulumiProvider[PulumiSchema, PulumiSchema] = &Bridge[PulumiSchema, PulumiSchema, TFSchema, TFSchema]{}
50+
51+
func (b *Bridge[CPS, PPS, CTFS, PTFS]) Check(
52+
news PulumiInput[CPS], olds PulumiCheckedInput[PPS],
53+
) PulumiCheckedInput[CPS] {
54+
return PulumiCheckedInput[CPS]{}
55+
}
56+
57+
func (b *Bridge[CPS, PPS, CTFS, PTFS]) CreatePreview(checkedInputs PulumiCheckedInput[CPS]) PulumiPreviewOutput[CPS] {
58+
tfConfig := b.pulumiCheckedInputToTFConfig(checkedInputs)
59+
emptyState := TFState[CTFS]{}
60+
tfPlannedState := b.TFProvider.PlanResourceChange(tfConfig, emptyState)
61+
return b.tfPlannedStateToPulumiPreviewOutput(tfPlannedState)
62+
}
63+
64+
func (b *Bridge[CPS, PPS, CTFS, PTFS]) Create(checkedInputs PulumiCheckedInput[CPS]) PulumiOutput[CPS] {
65+
tfConfig := b.pulumiCheckedInputToTFConfig(checkedInputs)
66+
emptyState := TFState[CTFS]{}
67+
tfPlannedState := b.TFProvider.PlanResourceChange(tfConfig, emptyState)
68+
tfState := b.TFProvider.ApplyResourceChange(tfConfig, emptyState, tfPlannedState)
69+
return b.tfStateToPulumiOutput(tfState)
70+
}
71+
72+
func (b *Bridge[CPS, PPS, CTFS, PTFS]) UpdatePreview(
73+
checkedInputs PulumiCheckedInput[CPS],
74+
state PulumiOutput[PPS],
75+
// oldInputs is unused
76+
_oldInputs PulumiCheckedInput[PPS],
77+
) PulumiPreviewOutput[CPS] {
78+
tfConfig := b.pulumiCheckedInputToTFConfig(checkedInputs)
79+
tfState := b.tfRawStateFromPulumiOutput(state)
80+
tfUpgradedState := b.TFProvider.UpgradeState(tfState)
81+
tfPlannedState := b.TFProvider.PlanResourceChange(tfConfig, tfUpgradedState)
82+
return b.tfPlannedStateToPulumiPreviewOutput(tfPlannedState)
83+
}
84+
85+
func (b *Bridge[CPS, PPS, CTFS, PTFS]) Update(
86+
checkedInputs PulumiCheckedInput[CPS],
87+
state PulumiOutput[PPS],
88+
// oldInputs is unused
89+
_oldInputs PulumiCheckedInput[PPS],
90+
) PulumiOutput[CPS] {
91+
tfConfig := b.pulumiCheckedInputToTFConfig(checkedInputs)
92+
tfState := b.tfRawStateFromPulumiOutput(state)
93+
tfUpgradedState := b.TFProvider.UpgradeState(tfState)
94+
tfPlannedState := b.TFProvider.PlanResourceChange(tfConfig, tfUpgradedState)
95+
tfNewState := b.TFProvider.ApplyResourceChange(tfConfig, tfUpgradedState, tfPlannedState)
96+
return b.tfStateToPulumiOutput(tfNewState)
97+
}
98+
99+
func (b *Bridge[CPS, PPS, CTFS, PTFS]) DeletePreview(state PulumiOutput[PPS]) {
100+
tfState := b.tfRawStateFromPulumiOutput(state)
101+
upgradedState := b.TFProvider.UpgradeState(tfState)
102+
emptyConfig := TFConfig[CTFS]{}
103+
b.TFProvider.PlanResourceChange(emptyConfig, upgradedState)
104+
}
105+
106+
func (b *Bridge[CPS, PPS, CTFS, PTFS]) Delete(state PulumiOutput[PPS]) {
107+
tfState := b.tfRawStateFromPulumiOutput(state)
108+
upgradedState := b.TFProvider.UpgradeState(tfState)
109+
emptyConfig := TFConfig[CTFS]{}
110+
b.TFProvider.ApplyResourceChange(emptyConfig, upgradedState, TFPlannedState[CTFS]{})
111+
}
112+
113+
func (b *Bridge[CPS, PPS, CTFS, PTFS]) Diff(
114+
oldState PulumiOutput[PPS],
115+
oldInputs PulumiCheckedInput[PPS],
116+
newCheckedInputs PulumiCheckedInput[CPS],
117+
) (PulumiDiff[CPS], PulumiDetailedDiff[CPS, PPS]) {
118+
tfState := b.tfRawStateFromPulumiOutput(oldState)
119+
tfUpgradedState := b.TFProvider.UpgradeState(tfState)
120+
tfConfig := b.pulumiCheckedInputToTFConfig(newCheckedInputs)
121+
tfPlannedState := b.TFProvider.PlanResourceChange(tfConfig, tfUpgradedState)
122+
plannedState := b.tfPlannedStateToPulumiPreviewOutput(tfPlannedState)
123+
124+
tfDiff := b.TFProvider.Diff(tfUpgradedState, tfPlannedState)
125+
126+
translateTFDiffToPulumiDiff := func(TFDiff[CTFS]) PulumiDiff[CPS] {
127+
return PulumiDiff[CPS]{}
128+
}
129+
130+
producePulumiDetailedDiff := func(
131+
_ TFDiff[CTFS],
132+
oldState PulumiOutput[PPS],
133+
newCheckedInputs PulumiCheckedInput[CPS],
134+
_ PulumiPreviewOutput[CPS],
135+
) PulumiDetailedDiff[CPS, PPS] {
136+
// This is not easy as we first need to diff PulumiOutput[PPS] against PulumiPreviewOutput[CPS]
137+
// and then we need to map this back to the PulumiCheckedInput[CPS]
138+
// PulumiPreviewOutput and PulumiCheckedInput are not directly comparable
139+
return PulumiDetailedDiff[CPS, PPS]{
140+
oldState: oldState,
141+
newCheckedInputs: newCheckedInputs,
142+
}
143+
}
144+
145+
pulumiDiff := translateTFDiffToPulumiDiff(tfDiff)
146+
pulumiDetailedDiff := producePulumiDetailedDiff(tfDiff, oldState, newCheckedInputs, plannedState)
147+
148+
return pulumiDiff, pulumiDetailedDiff
149+
}
150+
151+
func (b *Bridge[CPS, PPS, CTFS, PTFS]) ReadForImport(id string) (PulumiOutput[CPS], PulumiInput[CPS]) {
152+
tfState := b.TFProvider.Importer(id)
153+
state := b.tfStateToPulumiOutput(tfState)
154+
inputs := b.extractInputsFromOutputs(PulumiCheckedInput[PPS]{}, state)
155+
return state, inputs
156+
}
157+
158+
func (b *Bridge[CPS, PPS, CTFS, PTFS]) ReadForRefresh(
159+
inputs PulumiCheckedInput[PPS], state PulumiOutput[PPS],
160+
) (PulumiInput[CPS], PulumiOutput[CPS]) {
161+
tfState := b.tfRawStateFromPulumiOutput(state)
162+
tfUpgradedState := b.TFProvider.UpgradeState(tfState)
163+
164+
tfNewState := b.TFProvider.ReadResource(tfUpgradedState)
165+
166+
newPulumiState := b.tfStateToPulumiOutput(tfNewState)
167+
168+
newPulumiInputs := b.extractInputsFromOutputs(inputs, newPulumiState)
169+
return newPulumiInputs, newPulumiState
170+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
package protocolspec
2+
3+
func getUserInputs[S PulumiSchema]() PulumiInput[S] {
4+
return PulumiInput[S]{}
5+
}
6+
7+
func getOldInputs[S PulumiSchema]() PulumiCheckedInput[S] {
8+
return PulumiCheckedInput[S]{}
9+
}
10+
11+
func getOldState[S PulumiSchema]() PulumiOutput[S] {
12+
return PulumiOutput[S]{}
13+
}
14+
15+
func CreateResource() {
16+
type PS struct{}
17+
type TFS struct{}
18+
prov := &Bridge[PS, PS, TFS, TFS]{}
19+
userInputs := getUserInputs[PS]()
20+
oldInputs := getOldInputs[PS]()
21+
22+
checkedInputs := prov.Check(userInputs, oldInputs)
23+
previewOutputs := prov.CreatePreview(checkedInputs)
24+
25+
// previewOutputs is discarded?
26+
_ = previewOutputs
27+
28+
// Note the engine does not display unknowns in the preview
29+
displayPreview(checkedInputs, PulumiOutput[PS]{}, PulumiDetailedDiff[PS, PS]{})
30+
31+
prov.Create(checkedInputs)
32+
}
33+
34+
func UpdateResourceNoUpgrade() {
35+
type PS struct{}
36+
type TFS struct{}
37+
prov := &Bridge[PS, PS, TFS, TFS]{}
38+
userInputs := getUserInputs[PS]()
39+
oldState := getOldState[PS]()
40+
oldInputs := getOldInputs[PS]()
41+
42+
checkedInputs := prov.Check(userInputs, oldInputs)
43+
44+
diff, detailedDiff := prov.Diff(oldState, oldInputs, checkedInputs)
45+
if diff.HasChanges {
46+
previewOutputs := prov.UpdatePreview(checkedInputs, oldState, oldInputs)
47+
// previewOutputs is discarded?
48+
_ = previewOutputs
49+
}
50+
51+
displayPreview(checkedInputs, oldState, detailedDiff)
52+
53+
prov.Update(checkedInputs, oldState, oldInputs)
54+
}
55+
56+
func UpdateResourceWithUpgrade() {
57+
type CPS struct{}
58+
type CTFS struct{}
59+
type PPS struct{}
60+
type PTFS struct{}
61+
prov := &Bridge[CPS, PPS, CTFS, PTFS]{}
62+
userInputs := getUserInputs[CPS]()
63+
oldState := getOldState[PPS]()
64+
oldInputs := getOldInputs[PPS]()
65+
66+
checkedInputs := prov.Check(userInputs, oldInputs)
67+
68+
diff, detailedDiff := prov.Diff(oldState, oldInputs, checkedInputs)
69+
if diff.HasChanges {
70+
previewOutputs := prov.UpdatePreview(checkedInputs, oldState, oldInputs)
71+
// previewOutputs is discarded?
72+
_ = previewOutputs
73+
}
74+
75+
displayPreview(checkedInputs, oldState, detailedDiff)
76+
77+
prov.Update(checkedInputs, oldState, oldInputs)
78+
}
79+
80+
func DeleteResourceNoUpgrade() {
81+
type PS struct{}
82+
type TFS struct{}
83+
prov := &Bridge[PS, PS, TFS, TFS]{}
84+
oldState := getOldState[PS]()
85+
86+
prov.Delete(oldState)
87+
}
88+
89+
func DeleteResourceWithUpgrade() {
90+
type CPS struct{}
91+
_ = CPS{} // unused
92+
type CTFS struct{}
93+
_ = CTFS{} // unused
94+
type PPS struct{}
95+
type PTFS struct{}
96+
97+
// Note the engine currently uses the old provider for delete
98+
// TODO: Is this always the case?
99+
prov := &Bridge[PPS, PPS, PTFS, PTFS]{}
100+
oldState := getOldState[PPS]()
101+
102+
prov.Delete(oldState)
103+
}
104+
105+
func ImportResource() {
106+
type PS struct{}
107+
type TFS struct{}
108+
prov := &Bridge[PS, PS, TFS, TFS]{}
109+
id := "imported-resource"
110+
111+
prov.ReadForImport(id)
112+
}
113+
114+
func RefreshNoUpgrade() {
115+
type PS struct{}
116+
type TFS struct{}
117+
prov := &Bridge[PS, PS, TFS, TFS]{}
118+
119+
inputs := getOldInputs[PS]()
120+
state := getOldState[PS]()
121+
122+
readInputs, readState := prov.ReadForRefresh(inputs, state)
123+
124+
readCheckedInputs := prov.Check(readInputs, inputs)
125+
126+
//nolint:lll
127+
// parameter inversion here: https://pulumi-developer-docs.readthedocs.io/latest/developer-docs/providers/implementers-guide.html#refresh
128+
diff, detailedDiff := prov.Diff(readState, readCheckedInputs, inputs)
129+
if diff.HasChanges {
130+
previewOutputs := prov.UpdatePreview(readCheckedInputs, state, inputs)
131+
// previewOutputs is discarded?
132+
_ = previewOutputs
133+
}
134+
135+
displayPreview(readCheckedInputs, state, detailedDiff)
136+
// state is replaced here.
137+
}
138+
139+
func RefreshWithUpgrade() {
140+
type CPS struct{}
141+
_ = CPS{} // unused
142+
type CTFS struct{}
143+
_ = CTFS{} // unused
144+
type PPS struct{}
145+
type PTFS struct{}
146+
147+
// Note the engine currently uses the old provider for refresh
148+
// TODO: Is this always the case?
149+
prov := &Bridge[PPS, PPS, PTFS, PTFS]{}
150+
state := getOldState[PPS]()
151+
inputs := getOldInputs[PPS]()
152+
153+
readInputs, readState := prov.ReadForRefresh(inputs, state)
154+
155+
readCheckedInputs := prov.Check(readInputs, inputs)
156+
157+
//nolint:lll
158+
// parameter inversion here: https://pulumi-developer-docs.readthedocs.io/latest/developer-docs/providers/implementers-guide.html#refresh
159+
diff, detailedDiff := prov.Diff(readState, readCheckedInputs, inputs)
160+
if diff.HasChanges {
161+
previewOutputs := prov.UpdatePreview(readCheckedInputs, state, inputs)
162+
// previewOutputs is discarded?
163+
_ = previewOutputs
164+
}
165+
166+
displayPreview(readCheckedInputs, state, detailedDiff)
167+
168+
// TODO: Changes in https://github.com/pulumi/pulumi/issues/19335 ?
169+
}

0 commit comments

Comments
 (0)