Skip to content

protocol spec #3049

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 167 additions & 0 deletions pkg/internal/tests/protocolspec/bridge.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
package protocolspec

// CPS stands for Current Pulumi Schema
// PPS stands for Previous Pulumi Schema
// CTFS stands for Current TF Schema
// PTFS stands for Previous TF Schema
type Bridge[CPS PulumiSchema, PPS PulumiSchema, CTFS TFSchema, PTFS TFSchema] struct {
TFProvider TFProviderWithUpgradeState[CTFS, PTFS]
}

func (b *Bridge[CPS, PPS, CTFS, PTFS]) getCurrentBridge() Bridge[CPS, CPS, CTFS, CTFS] {
return Bridge[CPS, CPS, CTFS, CTFS]{
TFProvider: b.TFProvider.GetCurrentProvider(),
}
}

func (b *Bridge[CPS, PPS, CTFS, PTFS]) tfStateToPulumiOutput(TFState[CTFS]) PulumiOutput[CPS] {
return PulumiOutput[CPS]{}
}

func (b *Bridge[CPS, PPS, CTFS, PTFS]) tfPlannedStateToPulumiPreviewOutput(
TFPlannedState[CTFS],
) PulumiPreviewOutput[CPS] {
return PulumiPreviewOutput[CPS]{}
}

// This was recently replaced by tfRawStateFromPulumiOutput
func (b *Bridge[CPS, PPS, CTFS, PTFS]) pulumiOutputToTFState(PulumiOutput[CPS]) TFState[CTFS] {
return TFState[CTFS]{}
}

func (b *Bridge[CPS, PPS, CTFS, PTFS]) pulumiCheckedInputToTFConfig(PulumiCheckedInput[CPS]) TFConfig[CTFS] {
return TFConfig[CTFS]{}
}

func (b *Bridge[CPS, PPS, CTFS, PTFS]) tfRawStateFromPulumiOutput(PulumiOutput[PPS]) TFState[PTFS] {
return TFState[PTFS]{}
}

// extractInputsFromOutputs is not precise and has some assumptions and approximations
// Especially when there are no past inputs
func (b *Bridge[CPS, PPS, CTFS, PTFS]) extractInputsFromOutputs(
oldInputs PulumiCheckedInput[PPS],
outputs PulumiOutput[CPS],
) PulumiInput[CPS] {
return PulumiInput[CPS]{}
}

var _ PulumiProvider[PulumiSchema, PulumiSchema] = &Bridge[PulumiSchema, PulumiSchema, TFSchema, TFSchema]{}

func (b *Bridge[CPS, PPS, CTFS, PTFS]) Check(
news PulumiInput[CPS], olds PulumiCheckedInput[PPS],
) PulumiCheckedInput[CPS] {
return PulumiCheckedInput[CPS]{}
}

func (b *Bridge[CPS, PPS, CTFS, PTFS]) CreatePreview(checkedInputs PulumiCheckedInput[CPS]) PulumiPreviewOutput[CPS] {
tfConfig := b.pulumiCheckedInputToTFConfig(checkedInputs)
emptyState := TFState[CTFS]{}
tfPlannedState := b.TFProvider.PlanResourceChange(tfConfig, emptyState)
return b.tfPlannedStateToPulumiPreviewOutput(tfPlannedState)
}

func (b *Bridge[CPS, PPS, CTFS, PTFS]) Create(checkedInputs PulumiCheckedInput[CPS]) PulumiOutput[CPS] {
tfConfig := b.pulumiCheckedInputToTFConfig(checkedInputs)
emptyState := TFState[CTFS]{}
tfPlannedState := b.TFProvider.PlanResourceChange(tfConfig, emptyState)
tfState := b.TFProvider.ApplyResourceChange(tfConfig, emptyState, tfPlannedState)
return b.tfStateToPulumiOutput(tfState)
}

func (b *Bridge[CPS, PPS, CTFS, PTFS]) UpdatePreview(
checkedInputs PulumiCheckedInput[CPS],
state PulumiOutput[PPS],
// oldInputs is unused
_oldInputs PulumiCheckedInput[PPS],
) PulumiPreviewOutput[CPS] {
tfConfig := b.pulumiCheckedInputToTFConfig(checkedInputs)
tfState := b.tfRawStateFromPulumiOutput(state)
tfUpgradedState := b.TFProvider.UpgradeState(tfState)
tfPlannedState := b.TFProvider.PlanResourceChange(tfConfig, tfUpgradedState)
return b.tfPlannedStateToPulumiPreviewOutput(tfPlannedState)
}

func (b *Bridge[CPS, PPS, CTFS, PTFS]) Update(
checkedInputs PulumiCheckedInput[CPS],
state PulumiOutput[PPS],
// oldInputs is unused
_oldInputs PulumiCheckedInput[PPS],
) PulumiOutput[CPS] {
tfConfig := b.pulumiCheckedInputToTFConfig(checkedInputs)
tfState := b.tfRawStateFromPulumiOutput(state)
tfUpgradedState := b.TFProvider.UpgradeState(tfState)
tfPlannedState := b.TFProvider.PlanResourceChange(tfConfig, tfUpgradedState)
tfNewState := b.TFProvider.ApplyResourceChange(tfConfig, tfUpgradedState, tfPlannedState)
return b.tfStateToPulumiOutput(tfNewState)
}

func (b *Bridge[CPS, PPS, CTFS, PTFS]) DeletePreview(state PulumiOutput[PPS]) {
tfState := b.tfRawStateFromPulumiOutput(state)
upgradedState := b.TFProvider.UpgradeState(tfState)
emptyConfig := TFConfig[CTFS]{}
b.TFProvider.PlanResourceChange(emptyConfig, upgradedState)
}

func (b *Bridge[CPS, PPS, CTFS, PTFS]) Delete(state PulumiOutput[PPS]) {
tfState := b.tfRawStateFromPulumiOutput(state)
upgradedState := b.TFProvider.UpgradeState(tfState)
emptyConfig := TFConfig[CTFS]{}
b.TFProvider.ApplyResourceChange(emptyConfig, upgradedState, TFPlannedState[CTFS]{})
}

func (b *Bridge[CPS, PPS, CTFS, PTFS]) Diff(
oldState PulumiOutput[PPS],
oldInputs PulumiCheckedInput[PPS],
newCheckedInputs PulumiCheckedInput[CPS],
) (PulumiDiff[CPS], PulumiDetailedDiff[CPS, PPS]) {
tfState := b.tfRawStateFromPulumiOutput(oldState)
tfUpgradedState := b.TFProvider.UpgradeState(tfState)
tfConfig := b.pulumiCheckedInputToTFConfig(newCheckedInputs)
tfPlannedState := b.TFProvider.PlanResourceChange(tfConfig, tfUpgradedState)
plannedState := b.tfPlannedStateToPulumiPreviewOutput(tfPlannedState)

tfDiff := b.TFProvider.Diff(tfUpgradedState, tfPlannedState)

translateTFDiffToPulumiDiff := func(TFDiff[CTFS]) PulumiDiff[CPS] {
return PulumiDiff[CPS]{}
}

producePulumiDetailedDiff := func(
_ TFDiff[CTFS],
oldState PulumiOutput[PPS],
newCheckedInputs PulumiCheckedInput[CPS],
_ PulumiPreviewOutput[CPS],
) PulumiDetailedDiff[CPS, PPS] {
// This is not easy as we first need to diff PulumiOutput[PPS] against PulumiPreviewOutput[CPS]
// and then we need to map this back to the PulumiCheckedInput[CPS]
// PulumiPreviewOutput and PulumiCheckedInput are not directly comparable
return PulumiDetailedDiff[CPS, PPS]{
oldState: oldState,
newCheckedInputs: newCheckedInputs,
}
}

pulumiDiff := translateTFDiffToPulumiDiff(tfDiff)
pulumiDetailedDiff := producePulumiDetailedDiff(tfDiff, oldState, newCheckedInputs, plannedState)

return pulumiDiff, pulumiDetailedDiff
}

func (b *Bridge[CPS, PPS, CTFS, PTFS]) ReadForImport(id string) (PulumiOutput[CPS], PulumiInput[CPS]) {
tfState := b.TFProvider.Importer(id)
state := b.tfStateToPulumiOutput(tfState)
inputs := b.extractInputsFromOutputs(PulumiCheckedInput[PPS]{}, state)
return state, inputs
}

func (b *Bridge[CPS, PPS, CTFS, PTFS]) ReadForRefresh(
inputs PulumiCheckedInput[PPS], state PulumiOutput[PPS],
) (PulumiInput[CPS], PulumiOutput[CPS]) {
tfState := b.tfRawStateFromPulumiOutput(state)
tfUpgradedState := b.TFProvider.UpgradeState(tfState)
tfNewState := b.TFProvider.ReadResource(tfUpgradedState)
newPulumiState := b.tfStateToPulumiOutput(tfNewState)
newPulumiInputs := b.extractInputsFromOutputs(inputs, newPulumiState)
return newPulumiInputs, newPulumiState
}
140 changes: 140 additions & 0 deletions pkg/internal/tests/protocolspec/bridgev2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package protocolspec

type BridgeV2[CPS PulumiSchema, CTFS TFSchema] struct {
TFProvider TFProvider[CTFS]
}

var _ PulumiProviderV2[PulumiSchema] = &BridgeV2[PulumiSchema, TFSchema]{}

func (b *BridgeV2[CPS, CTFS]) tfStateToPulumiOutput(TFState[CTFS]) PulumiOutput[CPS] {
return PulumiOutput[CPS]{}
}

func (b *BridgeV2[CPS, CTFS]) tfPlannedStateToPulumiPreviewOutput(
TFPlannedState[CTFS],
) PulumiPreviewOutput[CPS] {
return PulumiPreviewOutput[CPS]{}
}

// This is new.
func (b *BridgeV2[CPS, CTFS]) pulumiPreviewOutputToTFPlannedState(PulumiPreviewOutput[CPS]) TFPlannedState[CTFS] {
return TFPlannedState[CTFS]{}
}

func (b *BridgeV2[CPS, CTFS]) pulumiInputToTFConfig(PulumiInput[CPS]) TFConfig[CTFS] {
return TFConfig[CTFS]{}
}

func (b *BridgeV2[CPS, CTFS]) tfRawStateFromPulumiOutput(PulumiOutput[CPS]) TFState[CTFS] {
return TFState[CTFS]{}
}

func (b *BridgeV2[CPS, CTFS]) Check(news PulumiInput[CPS]) PulumiInput[CPS] {
return PulumiInput[CPS]{}
}

func (b *BridgeV2[CPS, CTFS]) CreatePreview(inputs PulumiInput[CPS]) PulumiPreviewOutput[CPS] {
tfConfig := b.pulumiInputToTFConfig(inputs)
emptyState := TFState[CTFS]{}
tfPlannedState := b.TFProvider.PlanResourceChange(tfConfig, emptyState)
return b.tfPlannedStateToPulumiPreviewOutput(tfPlannedState)
}

func (b *BridgeV2[CPS, CTFS]) Create(inputs PulumiInput[CPS]) PulumiOutput[CPS] {
tfConfig := b.pulumiInputToTFConfig(inputs)
emptyState := TFState[CTFS]{}
tfPlannedState := b.TFProvider.PlanResourceChange(tfConfig, emptyState)
tfState := b.TFProvider.ApplyResourceChange(tfConfig, emptyState, tfPlannedState)
return b.tfStateToPulumiOutput(tfState)
}

func (b *BridgeV2[CPS, CTFS]) UpdatePreview(inputs PulumiInput[CPS], state PulumiOutput[CPS]) PulumiPreviewOutput[CPS] {
tfConfig := b.pulumiInputToTFConfig(inputs)
tfState := b.tfRawStateFromPulumiOutput(state)
tfPlannedState := b.TFProvider.PlanResourceChange(tfConfig, tfState)
return b.tfPlannedStateToPulumiPreviewOutput(tfPlannedState)
}

func (b *BridgeV2[CPS, CTFS]) Update(inputs PulumiInput[CPS], state PulumiOutput[CPS]) PulumiOutput[CPS] {
tfConfig := b.pulumiInputToTFConfig(inputs)
tfState := b.tfRawStateFromPulumiOutput(state)
tfPlannedState := b.TFProvider.PlanResourceChange(tfConfig, tfState)
tfState = b.TFProvider.ApplyResourceChange(tfConfig, tfState, tfPlannedState)
return b.tfStateToPulumiOutput(tfState)
}

func (b *BridgeV2[CPS, CTFS]) DeletePreview(state PulumiOutput[CPS]) PulumiPreviewOutput[CPS] {
tfConfig := TFConfig[CTFS]{}
tfState := b.tfRawStateFromPulumiOutput(state)
tfPlannedState := b.TFProvider.PlanResourceChange(tfConfig, tfState)
return b.tfPlannedStateToPulumiPreviewOutput(tfPlannedState)
}

func (b *BridgeV2[CPS, CTFS]) Delete(state PulumiOutput[CPS]) PulumiOutput[CPS] {
tfConfig := TFConfig[CTFS]{}
tfState := b.tfRawStateFromPulumiOutput(state)
tfPlannedState := b.TFProvider.PlanResourceChange(tfConfig, tfState)
tfState = b.TFProvider.ApplyResourceChange(tfConfig, tfState, tfPlannedState)
return b.tfStateToPulumiOutput(tfState)
}

func (b *BridgeV2[CPS, CTFS]) Diff(oldState PulumiOutput[CPS], plannedState PulumiPreviewOutput[CPS]) (PulumiDiff[CPS], PulumiDetailedDiffV2[CPS]) {
tfState := b.tfRawStateFromPulumiOutput(oldState)
tfPlannedState := b.pulumiPreviewOutputToTFPlannedState(plannedState)
tfDiff := b.TFProvider.Diff(tfState, tfPlannedState)

translateTFDiffToPulumiDiff := func(TFDiff[CTFS]) PulumiDiff[CPS] {
return PulumiDiff[CPS]{}
}

producePulumiDetailedDiff := func(
oldState PulumiOutput[CPS],
plannedState PulumiPreviewOutput[CPS],
) PulumiDetailedDiffV2[CPS] {
// The values here are in the same plane - much easier to produce a diff.
return PulumiDetailedDiffV2[CPS]{
OldState: oldState,
plannedState: plannedState,
}
}

pulumiDiff := translateTFDiffToPulumiDiff(tfDiff)
pulumiDetailedDiff := producePulumiDetailedDiff(oldState, plannedState)

return pulumiDiff, pulumiDetailedDiff
}

// extractInputsFromOutputs is not precise and has some assumptions and approximations
// Especially when there are no past inputs
func (b *BridgeV2[CPS, CTFS]) extractInputsFromOutputsNoInputs(
outputs PulumiOutput[CPS],
) PulumiInput[CPS] {
// guess
return PulumiInput[CPS]{}
}

func (b *BridgeV2[CPS, CTFS]) ReadForImport(id string) (PulumiOutput[CPS], PulumiInput[CPS]) {
tfState := b.TFProvider.Importer(id)
state := b.tfStateToPulumiOutput(tfState)
inputs := b.extractInputsFromOutputsNoInputs(state)
return state, inputs
}

func (b *BridgeV2[CPS, CTFS]) ReadForRefresh(state PulumiOutput[CPS]) (PulumiOutput[CPS]) {
tfState := b.tfRawStateFromPulumiOutput(state)
tfNewState := b.TFProvider.ReadResource(tfState)
newState := b.tfStateToPulumiOutput(tfNewState)
return newState
}

// The only method which needs to deal with old schema is UpgradeState.
type BridgeV2WithUpgrade[CPS PulumiSchema, PS PulumiSchema, CTFS TFSchema, PTS TFSchema] struct {
BridgeV2[CPS, CTFS]
TFProvider TFProviderWithUpgradeState[CTFS, PTS]
}

var _ PulumiProviderV2WithUpgrade[PulumiSchema, PulumiSchema] = &BridgeV2WithUpgrade[PulumiSchema, PulumiSchema, TFSchema, TFSchema]{}

func (b *BridgeV2WithUpgrade[CPS, PS, CTFS, PTS]) UpgradeState(state PulumiOutput[PS]) PulumiOutput[CPS] {
return PulumiOutput[CPS]{}
}
Loading
Loading