2018-03-21 20:43:21 +01:00
|
|
|
// Copyright 2016-2018, Pulumi Corporation. All rights reserved.
|
2017-06-07 01:42:14 +02:00
|
|
|
|
2017-10-16 21:04:35 +02:00
|
|
|
package stack
|
2017-06-07 01:42:14 +02:00
|
|
|
|
|
|
|
import (
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
|
2017-09-22 04:18:21 +02:00
|
|
|
"github.com/pulumi/pulumi/pkg/resource"
|
|
|
|
"github.com/pulumi/pulumi/pkg/tokens"
|
2017-06-07 01:42:14 +02:00
|
|
|
)
|
|
|
|
|
2018-02-22 00:11:21 +01:00
|
|
|
// TestDeploymentSerialization creates a basic snapshot of a given resource state.
|
2017-06-07 01:42:14 +02:00
|
|
|
func TestDeploymentSerialization(t *testing.T) {
|
2017-06-11 02:03:58 +02:00
|
|
|
res := resource.NewState(
|
2017-06-07 01:42:14 +02:00
|
|
|
tokens.Type("Test"),
|
2017-06-11 02:03:58 +02:00
|
|
|
resource.NewURN(
|
|
|
|
tokens.QName("test"),
|
2017-08-30 03:24:12 +02:00
|
|
|
tokens.PackageName("resource/test"),
|
2017-12-04 23:50:55 +01:00
|
|
|
tokens.Type(""),
|
2017-06-11 02:03:58 +02:00
|
|
|
tokens.Type("Test"),
|
|
|
|
tokens.QName("resource-x"),
|
|
|
|
),
|
Implement components
This change implements core support for "components" in the Pulumi
Fabric. This work is described further in pulumi/pulumi#340, where
we are still discussing some of the finer points.
In a nutshell, resources no longer imply external providers. It's
entirely possible to have a resource that logically represents
something but without having a physical manifestation that needs to
be tracked and managed by our typical CRUD operations.
For example, the aws/serverless/Function helper is one such type.
It aggregates Lambda-related resources and exposes a nice interface.
All of the Pulumi Cloud Framework resources are also examples.
To indicate that a resource does participate in the usual CRUD resource
provider, it simply derives from ExternalResource instead of Resource.
All resources now have the ability to adopt children. This is purely
a metadata/tagging thing, and will help us roll up displays, provide
attribution to the developer, and even hide aspects of the resource
graph as appropriate (e.g., when they are implementation details).
Our use of this capability is ultra limited right now; in fact, the
only place we display children is in the CLI output. For instance:
+ aws:serverless:Function: (create)
[urn=urn:pulumi:demo::serverless::aws:serverless:Function::mylambda]
=> urn:pulumi:demo::serverless::aws:iam/role:Role::mylambda-iamrole
=> urn:pulumi:demo::serverless::aws:iam/rolePolicyAttachment:RolePolicyAttachment::mylambda-iampolicy-0
=> urn:pulumi:demo::serverless::aws:lambda/function:Function::mylambda
The bit indicating whether a resource is external or not is tracked
in the resulting checkpoint file, along with any of its children.
2017-10-14 23:18:43 +02:00
|
|
|
true,
|
2017-10-05 23:08:35 +02:00
|
|
|
false,
|
2017-06-11 02:03:58 +02:00
|
|
|
resource.ID("test-resource-x"),
|
|
|
|
resource.NewPropertyMapFromMap(map[string]interface{}{
|
2017-06-07 01:42:14 +02:00
|
|
|
"in-nil": nil,
|
|
|
|
"in-bool": true,
|
|
|
|
"in-float64": float64(1.5),
|
|
|
|
"in-string": "lumilumilo",
|
|
|
|
"in-array": []interface{}{"a", true, float64(32)},
|
|
|
|
"in-empty-array": []interface{}{},
|
|
|
|
"in-map": map[string]interface{}{
|
|
|
|
"a": true,
|
|
|
|
"b": float64(88),
|
|
|
|
"c": "c-see-saw",
|
|
|
|
"d": "d-dee-daw",
|
|
|
|
},
|
|
|
|
"in-empty-map": map[string]interface{}{},
|
|
|
|
}),
|
2017-06-11 02:03:58 +02:00
|
|
|
resource.NewPropertyMapFromMap(map[string]interface{}{
|
2017-06-07 01:42:14 +02:00
|
|
|
"out-nil": nil,
|
|
|
|
"out-bool": false,
|
|
|
|
"out-float64": float64(76),
|
|
|
|
"out-string": "loyolumiloom",
|
|
|
|
"out-array": []interface{}{false, "zzxx"},
|
|
|
|
"out-empty-array": []interface{}{},
|
|
|
|
"out-map": map[string]interface{}{
|
|
|
|
"x": false,
|
|
|
|
"y": "z-zee-zaw",
|
|
|
|
"z": float64(999.9),
|
|
|
|
},
|
|
|
|
"out-empty-map": map[string]interface{}{},
|
|
|
|
}),
|
2017-11-20 19:08:59 +01:00
|
|
|
"",
|
Implement resource protection (#751)
This change implements resource protection, as per pulumi/pulumi#689.
The overall idea is that a resource can be marked as "protect: true",
which will prevent deletion of that resource for any reason whatsoever
(straight deletion, replacement, etc). This is expressed in the
program. To "unprotect" a resource, one must perform an update setting
"protect: false", and then afterwards, they can delete the resource.
For example:
let res = new MyResource("precious", { .. }, { protect: true });
Afterwards, the resource will display in the CLI with a lock icon, and
any attempts to remove it will fail in the usual ways (in planning or,
worst case, during an actual update).
This was done by adding a new ResourceOptions bag parameter to the
base Resource types. This is unfortunately a breaking change, but now
is the right time to take this one. We had been adding new settings
one by one -- like parent and dependsOn -- and this new approach will
set us up to add any number of additional settings down the road,
without needing to worry about breaking anything ever again.
This is related to protected stacks, as described in
pulumi/pulumi-service#399. Most likely this will serve as a foundational
building block that enables the coarser grained policy management.
2017-12-20 23:31:07 +01:00
|
|
|
false,
|
2018-02-22 21:52:50 +01:00
|
|
|
[]resource.URN{
|
|
|
|
resource.URN("foo:bar:baz"),
|
|
|
|
resource.URN("foo:bar:boo"),
|
|
|
|
},
|
2017-06-07 01:42:14 +02:00
|
|
|
)
|
|
|
|
|
2017-06-11 02:03:58 +02:00
|
|
|
dep := SerializeResource(res)
|
2017-06-07 01:42:14 +02:00
|
|
|
|
|
|
|
// assert some things about the deployment record:
|
|
|
|
assert.NotNil(t, dep)
|
|
|
|
assert.NotNil(t, dep.ID)
|
2017-06-11 02:03:58 +02:00
|
|
|
assert.Equal(t, resource.ID("test-resource-x"), dep.ID)
|
2017-06-07 01:42:14 +02:00
|
|
|
assert.Equal(t, tokens.Type("Test"), dep.Type)
|
2018-02-22 00:11:21 +01:00
|
|
|
assert.Equal(t, 2, len(dep.Dependencies))
|
|
|
|
assert.Equal(t, resource.URN("foo:bar:baz"), dep.Dependencies[0])
|
|
|
|
assert.Equal(t, resource.URN("foo:bar:boo"), dep.Dependencies[1])
|
2017-06-07 01:42:14 +02:00
|
|
|
|
|
|
|
// assert some things about the inputs:
|
|
|
|
assert.NotNil(t, dep.Inputs)
|
|
|
|
assert.Nil(t, dep.Inputs["in-nil"])
|
|
|
|
assert.NotNil(t, dep.Inputs["in-bool"])
|
|
|
|
assert.True(t, dep.Inputs["in-bool"].(bool))
|
|
|
|
assert.NotNil(t, dep.Inputs["in-float64"])
|
|
|
|
assert.Equal(t, float64(1.5), dep.Inputs["in-float64"].(float64))
|
|
|
|
assert.NotNil(t, dep.Inputs["in-string"])
|
|
|
|
assert.Equal(t, "lumilumilo", dep.Inputs["in-string"].(string))
|
|
|
|
assert.NotNil(t, dep.Inputs["in-array"])
|
|
|
|
assert.Equal(t, 3, len(dep.Inputs["in-array"].([]interface{})))
|
|
|
|
assert.Equal(t, "a", dep.Inputs["in-array"].([]interface{})[0])
|
|
|
|
assert.Equal(t, true, dep.Inputs["in-array"].([]interface{})[1])
|
|
|
|
assert.Equal(t, float64(32), dep.Inputs["in-array"].([]interface{})[2])
|
|
|
|
assert.NotNil(t, dep.Inputs["in-empty-array"])
|
|
|
|
assert.Equal(t, 0, len(dep.Inputs["in-empty-array"].([]interface{})))
|
|
|
|
assert.NotNil(t, dep.Inputs["in-map"])
|
|
|
|
inmap := dep.Inputs["in-map"].(map[string]interface{})
|
|
|
|
assert.Equal(t, 4, len(inmap))
|
|
|
|
assert.NotNil(t, inmap["a"])
|
|
|
|
assert.Equal(t, true, inmap["a"].(bool))
|
|
|
|
assert.NotNil(t, inmap["b"])
|
|
|
|
assert.Equal(t, float64(88), inmap["b"].(float64))
|
|
|
|
assert.NotNil(t, inmap["c"])
|
|
|
|
assert.Equal(t, "c-see-saw", inmap["c"].(string))
|
|
|
|
assert.NotNil(t, inmap["d"])
|
|
|
|
assert.Equal(t, "d-dee-daw", inmap["d"].(string))
|
|
|
|
assert.NotNil(t, dep.Inputs["in-empty-map"])
|
|
|
|
assert.Equal(t, 0, len(dep.Inputs["in-empty-map"].(map[string]interface{})))
|
|
|
|
|
|
|
|
// assert some things about the outputs:
|
|
|
|
assert.NotNil(t, dep.Outputs)
|
|
|
|
assert.Nil(t, dep.Outputs["out-nil"])
|
|
|
|
assert.NotNil(t, dep.Outputs["out-bool"])
|
|
|
|
assert.False(t, dep.Outputs["out-bool"].(bool))
|
|
|
|
assert.NotNil(t, dep.Outputs["out-float64"])
|
|
|
|
assert.Equal(t, float64(76), dep.Outputs["out-float64"].(float64))
|
|
|
|
assert.NotNil(t, dep.Outputs["out-string"])
|
|
|
|
assert.Equal(t, "loyolumiloom", dep.Outputs["out-string"].(string))
|
|
|
|
assert.NotNil(t, dep.Outputs["out-array"])
|
|
|
|
assert.Equal(t, 2, len(dep.Outputs["out-array"].([]interface{})))
|
|
|
|
assert.Equal(t, false, dep.Outputs["out-array"].([]interface{})[0])
|
|
|
|
assert.Equal(t, "zzxx", dep.Outputs["out-array"].([]interface{})[1])
|
|
|
|
assert.NotNil(t, dep.Outputs["out-empty-array"])
|
|
|
|
assert.Equal(t, 0, len(dep.Outputs["out-empty-array"].([]interface{})))
|
|
|
|
assert.NotNil(t, dep.Outputs["out-map"])
|
|
|
|
outmap := dep.Outputs["out-map"].(map[string]interface{})
|
|
|
|
assert.Equal(t, 3, len(outmap))
|
|
|
|
assert.NotNil(t, outmap["x"])
|
|
|
|
assert.Equal(t, false, outmap["x"].(bool))
|
|
|
|
assert.NotNil(t, outmap["y"])
|
|
|
|
assert.Equal(t, "z-zee-zaw", outmap["y"].(string))
|
|
|
|
assert.NotNil(t, outmap["z"])
|
|
|
|
assert.Equal(t, float64(999.9), outmap["z"].(float64))
|
|
|
|
assert.NotNil(t, dep.Outputs["out-empty-map"])
|
|
|
|
assert.Equal(t, 0, len(dep.Outputs["out-empty-map"].(map[string]interface{})))
|
|
|
|
}
|