pulumi/examples/dynamic-provider/simple/index.ts
Sean Gillespie 2c479c172d
Lift snapshot management out of the engine and serialize writes to snapshot (#1069)
* Lift snapshot management out of the engine

This PR is a prerequisite for parallelism by addressing a major problem
that the engine has to deal with when performing parallel resource
construction: parallel mutation of the global snapshot. This PR adds
a `SnapshotManager` type that is responsible for maintaining and
persisting the current resource snapshot. It serializes all reads and
writes to the global snapshot and persists the snapshot to persistent
storage upon every write.

As a side-effect of this, the core engine no longer needs to know about
snapshot management at all; all snapshot operations can be handled as
callbacks on deployment events. This will greatly simplify the
parallelization of the core engine.

Worth noting is that the core engine will still need to be able to read
the current snapshot, since it is interested in the dependency graphs
contained within. The full implications of that are out of scope of this
PR.

Remove dead code, Steps no longer need a reference to the plan iterator that created them

Fixing various issues that arise when bringing up pulumi-aws

Line length broke the build

Code review: remove dead field, fix yaml name error

Rebase against master, provide implementation of StackPersister for cloud backend

Code review feedback: comments on MutationStatus, style in snapshot.go

Code review feedback: move SnapshotManager to pkg/backend, change engine to use an interface SnapshotManager

Code review feedback: use a channel for synchronization

Add a comment and a new test

* Maintain two checkpoints, an immutable base and a mutable delta, and
periodically merge the two to produce snapshots

* Add a lot of tests - covers all of the non-error paths of BeginMutation and End

* Fix a test resource provider

* Add a few tests, fix a few issues

* Rebase against master, fixed merge
2018-04-12 09:55:34 -07:00

85 lines
3.4 KiB
TypeScript

// Copyright 2016-2018, Pulumi Corporation. All rights reserved.
import * as pulumi from "@pulumi/pulumi";
import * as dynamic from "@pulumi/pulumi/dynamic";
class OperatorProvider implements dynamic.ResourceProvider {
private op: (l: number, r: number) => any;
constructor(op: (l: number, r: number) => any) {
this.op = op;
}
public check(olds: any, news: any) { return Promise.resolve({ inputs: news }); }
public diff(id: pulumi.ID, olds: any, news: any) { return Promise.resolve({}); }
public delete(id: pulumi.ID, props: any) { return Promise.resolve(); }
public create(inputs: any) { return Promise.resolve({ id: "0", outs: this.op(Number(inputs.left), Number(inputs.right)) }); }
public update(id: string, olds: any, news: any) { return Promise.resolve({ outs: this.op(Number(news.left), Number(news.right)) }); }
}
class DivProvider extends OperatorProvider {
constructor() {
super((left: number, right: number) => <any>{ quotient: Math.floor(left / right), remainder: left % right });
}
public async check(olds: any, news: any) {
return {
inputs: news,
failures: news.right == 0 ? [ { property: "right", reason: "divisor must be non-zero" } ] : [],
}
}
}
class Add extends dynamic.Resource {
public readonly sum: pulumi.Output<number>;
private static provider = new OperatorProvider((left: number, right: number) => <any>{ sum: left + right });
constructor(name: string, left: pulumi.Input<number>, right: pulumi.Input<number>) {
super(Add.provider, name, {left: left, right: right, sum: undefined}, undefined);
}
}
class Mul extends dynamic.Resource {
public readonly product: pulumi.Output<number>;
private static provider = new OperatorProvider((left: number, right: number) => <any>{ product: left * right });
constructor(name: string, left: pulumi.Input<number>, right: pulumi.Input<number>) {
super(Mul.provider, name, {left: left, right: right, product: undefined}, undefined);
}
}
class Sub extends dynamic.Resource {
public readonly difference: pulumi.Output<number>;
private static provider = new OperatorProvider((left: number, right: number) => <any>{ difference: left - right });
constructor(name: string, left: pulumi.Input<number>, right: pulumi.Input<number>) {
super(Sub.provider, name, {left: left, right: right, difference: undefined}, undefined);
}
}
class Div extends dynamic.Resource {
public readonly quotient: pulumi.Output<number>;
public readonly remainder: pulumi.Output<number>;
private static provider = new DivProvider();
constructor(name: string, left: pulumi.Input<number>, right: pulumi.Input<number>) {
super(Div.provider, name, {left: left, right: right, quotient: undefined, remainder: undefined}, undefined);
}
}
let config = new pulumi.Config("simple");
let w = Number(config.require("w")), x = Number(config.require("x")), y = Number(config.require("y"));
let sum = new Add("sum", x, y);
let square = new Mul("square", sum.sum, sum.sum);
let diff = new Sub("diff", square.product, w);
let divrem = new Div("divrem", diff.difference, sum.sum);
let result = new Add("result", divrem.quotient, divrem.remainder);
export let outputSum: pulumi.Output<number> = result.sum;
result.sum.apply(result => {
console.log(`((x + y)^2 - w) / (x + y) + ((x + y)^2 - w) %% (x + y) = ${result}`);
});