PR feedback

This commit is contained in:
Pat Gavlin 2017-10-14 14:29:49 -07:00
parent afd7c400ad
commit 1b4ed6cce3
5 changed files with 61 additions and 41 deletions

View file

@ -1,21 +1,22 @@
// Copyright 2016-2017, Pulumi Corporation. All rights reserved.
import * as pulumi from "pulumi";
import * as dynamic from "pulumi/dynamic";
class OperatorCallbacks implements pulumi.ProviderCallbacks {
class OperatorCallbacks implements dynamic.ResourceProvider {
private op: (l: number, r: number) => any;
constructor(op: (l: number, r: number) => any) {
this.op = op;
}
check = (inputs: any) => Promise.resolve(new pulumi.CheckResult(undefined, []));
diff = (id: pulumi.ID, olds: any, news: any) => Promise.resolve(new pulumi.DiffResult([], []));
check = (inputs: any) => Promise.resolve(new dynamic.CheckResult(undefined, []));
diff = (id: pulumi.ID, olds: any, news: any) => Promise.resolve(new dynamic.DiffResult([], []));
delete = (id: pulumi.ID, props: any) => Promise.resolve();
create = (inputs: any) => Promise.resolve(new pulumi.CreateResult("0", this.op(Number(inputs.left), Number(inputs.right))));
create = (inputs: any) => Promise.resolve(new dynamic.CreateResult("0", this.op(Number(inputs.left), Number(inputs.right))));
update = (id: string, olds: any, news: any) => Promise.resolve(new pulumi.UpdateResult(this.op(Number(news.left), Number(news.right))));
update = (id: string, olds: any, news: any) => Promise.resolve(new dynamic.UpdateResult(this.op(Number(news.left), Number(news.right))));
}
class DivCallbacks extends OperatorCallbacks {
@ -23,10 +24,10 @@ class DivCallbacks extends OperatorCallbacks {
super((left: number, right: number) => <any>{ quotient: Math.floor(left / right), remainder: left % right });
}
check = (ins: any) => Promise.resolve(new pulumi.CheckResult(undefined, ins.right == 0 ? [ new pulumi.CheckFailure("right", "divisor must be non-zero") ] : []));
check = (ins: any) => Promise.resolve(new dynamic.CheckResult(undefined, ins.right == 0 ? [ new dynamic.CheckFailure("right", "divisor must be non-zero") ] : []));
}
class Add extends pulumi.DynamicResource {
class Add extends dynamic.Resource {
public readonly sum: pulumi.Computed<number>;
private static callbacks = new OperatorCallbacks((left: number, right: number) => <any>{ sum: left + right });
@ -36,7 +37,7 @@ class Add extends pulumi.DynamicResource {
}
}
class Mul extends pulumi.DynamicResource {
class Mul extends dynamic.Resource {
public readonly product: pulumi.Computed<number>;
private static callbacks = new OperatorCallbacks((left: number, right: number) => <any>{ product: left * right });
@ -46,7 +47,7 @@ class Mul extends pulumi.DynamicResource {
}
}
class Sub extends pulumi.DynamicResource {
class Sub extends dynamic.Resource {
public readonly difference: pulumi.Computed<number>;
private static callbacks = new OperatorCallbacks((left: number, right: number) => <any>{ difference: left - right });
@ -56,7 +57,7 @@ class Sub extends pulumi.DynamicResource {
}
}
class Div extends pulumi.DynamicResource {
class Div extends dynamic.Resource {
public readonly quotient: pulumi.Computed<number>;
public readonly remainder: pulumi.Computed<number>;

View file

@ -19,10 +19,11 @@ const structproto = require("google-protobuf/google/protobuf/struct_pb.js");
const provproto = require("../../proto/provider_pb.js");
const provrpc = require("../../proto/provider_grpc_pb.js");
const callbacksKey: string = "dynamic:runtime:callbacks";
const providerKey: string = "__provider";
function getCallbacks(props: any): dynamic.ProviderCallbacks {
return requireFromString(props[callbacksKey]).handler();
function getProvider(props: any): dynamic.ResourceProvider {
// TODO[pulumi/pulumi#414]: investigate replacing requireFromString with eval
return requireFromString(props[providerKey]).handler();
}
function configureRPC(call: any, callback: any): void {
@ -42,9 +43,9 @@ async function checkRPC(call: any, callback: any): Promise<void> {
const resp = new provproto.CheckResponse();
const props = req.getProperties().toJavaScript();
const callbacks = getCallbacks(props);
const provider = getProvider(props);
const result = await callbacks.check(props);
const result = await provider.check(props);
if (result.defaults) {
resp.setDefaults(structproto.Struct.fromJavaScript(result.defaults));
}
@ -75,12 +76,12 @@ async function diffRPC(call: any, callback: any): Promise<void> {
const olds = req.getOlds().toJavaScript();
const news = req.getNews().toJavaScript();
if (olds[callbacksKey] !== news[callbacksKey]) {
resp.setReplacesList([ callbacksKey ]);
if (olds[providerKey] !== news[providerKey]) {
resp.setReplacesList([ providerKey ]);
} else {
const callbacks = getCallbacks(olds);
const provider = getProvider(olds);
const result: any = await callbacks.diff(req.getId(), olds, news);
const result: any = await provider.diff(req.getId(), olds, news);
if (result.replaces.length !== 0) {
resp.setReplacesList(result.replaces);
}
@ -99,9 +100,9 @@ async function createRPC(call: any, callback: any): Promise<void> {
const resp = new provproto.CreateResponse();
const props = req.getProperties().toJavaScript();
const callbacks = getCallbacks(props);
const provider = getProvider(props);
const result = await callbacks.create(props);
const result = await provider.create(props);
resp.setId(result.id);
if (result.outs) {
resp.setProperties(structproto.Struct.fromJavaScript(result.outs));
@ -121,12 +122,12 @@ async function updateRPC(call: any, callback: any): Promise<void> {
const olds = req.getOlds().toJavaScript();
const news = req.getNews().toJavaScript();
if (olds[callbacksKey] !== news[callbacksKey]) {
throw new Error("changes to callbacks should require replacement");
if (olds[providerKey] !== news[providerKey]) {
throw new Error("changes to provider should require replacement");
}
const callbacks = getCallbacks(olds);
const provider = getProvider(olds);
const result: any = await callbacks.update(req.getId(), olds, news);
const result: any = await provider.update(req.getId(), olds, news);
if (result.outs) {
resp.setProperties(structproto.Struct.fromJavaScript(result.outs));
}
@ -142,7 +143,7 @@ async function deleteRPC(call: any, callback: any): Promise<void> {
try {
const req: any = call.request;
const props: any = req.getProperties().toJavaScript();
await getCallbacks(props).delete(req.getId(), props);
await getProvider(props).delete(req.getId(), props);
callback(undefined, new emptyproto.Empty());
} catch (e) {
console.error(new Error().stack);

View file

@ -4,7 +4,7 @@ import * as resource from "./resource";
import * as runtime from "./runtime";
/**
* CheckResult represents the results of a call to `ProviderCallbacks.check`.
* CheckResult represents the results of a call to `ResourceProvider.check`.
*/
export class CheckResult {
/**
@ -30,7 +30,7 @@ export class CheckResult {
}
/**
* CheckFailure represents a single failure in the results of a call to `ProviderCallbacks.check`
* CheckFailure represents a single failure in the results of a call to `ResourceProvider.check`
*/
export class CheckFailure {
/**
@ -56,7 +56,7 @@ export class CheckFailure {
}
/**
* DiffResult represents the results of a call to `ProviderCallbacks.diff`.
* DiffResult represents the results of a call to `ResourceProvider.diff`.
*/
export class DiffResult {
/**
@ -82,7 +82,7 @@ export class DiffResult {
}
/**
* CreateResult represents the results of a call to `ProviderCallbacks.create`.
* CreateResult represents the results of a call to `ResourceProvider.create`.
*/
export class CreateResult {
/**
@ -108,7 +108,7 @@ export class CreateResult {
}
/**
* UpdateResult represents the results of a call to `ProviderCallbacks.update`.
* UpdateResult represents the results of a call to `ResourceProvider.update`.
*/
export class UpdateResult {
/**
@ -127,9 +127,9 @@ export class UpdateResult {
}
/**
* Provider represents an object that provides CRUD operations for a particular type of resource.
* ResourceProvider represents an object that provides CRUD operations for a particular type of resource.
*/
export interface ProviderCallbacks {
export interface ResourceProvider {
/**
* Check validates that the given property bag is valid for a resource of the given type.
*
@ -172,16 +172,34 @@ export interface ProviderCallbacks {
delete: (id: resource.ID, props: any) => Promise<void>;
}
export abstract class DynamicResource extends resource.Resource {
private static async serializeCallbacks(callbacks: ProviderCallbacks): Promise<string> {
return runtime.serializeJavaScriptText(await runtime.serializeClosure(() => callbacks));
/**
* Resource represents a Pulumi Resource that incorporates an inline implementation of the Resource's CRUD operations.
*/
export abstract class Resource extends resource.Resource {
private static async serializeProvider(provider: ResourceProvider): Promise<string> {
return runtime.serializeJavaScriptText(await runtime.serializeClosure(() => provider));
}
public constructor(callbacks: ProviderCallbacks,
/**
* Creates a new dynamic resource.
*
* @param provider The implementation of the resource's CRUD operations.
* @param name The name of the resource.
* @param props The arguments to use to populate the new resource. Must not define the reserved
* property "__provider".
* @param dependsOn Optional additional explicit dependencies on other resources.
*/
public constructor(provider: ResourceProvider,
name: string,
props: resource.ComputedValues,
dependsOn?: resource.Resource[]) {
props["dynamic:runtime:callbacks"] = DynamicResource.serializeCallbacks(callbacks);
super("dynamic:runtime:resource", name, props, dependsOn);
const providerKey: string = "__provider";
if (props[providerKey]) {
throw new Error("A dynamic resource must not define the __provider key");
}
props[providerKey] = Resource.serializeProvider(provider);
super("pulumi-nodejs:dynamic:Resource", name, props, dependsOn);
}
}

View file

@ -5,12 +5,12 @@ import "source-map-support/register";
// Export top-level elements.
export * from "./config";
export * from "./dynamic";
export * from "./resource";
// Export submodules individually.
import * as asset from "./asset";
import * as dynamic from "./dynamic";
import * as log from "./log";
import * as runtime from "./runtime";
export { asset, log, runtime };
export { asset, dynamic, log, runtime };