Skip to content
This repository has been archived by the owner on Jul 9, 2024. It is now read-only.

Support Template Data in Results #5

Merged
merged 8 commits into from
Nov 7, 2020
Merged
Show file tree
Hide file tree
Changes from 6 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
11 changes: 11 additions & 0 deletions component/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,14 @@ type Release interface {
// URL is the URL to access this release.
URL() string
}

// Template can be implemented by Artifact, Deployment, and Release. This
// will expose this information as available variables in the HCL configuration
// as well as functions in the `template`-prefixed family, such as `templatefile`.
//
// If Template is NOT implemented, we will automatically infer template data
// based on exported variables of the result value. This may not be desirable
// in which case you should implement Template and return nil.
type Template interface {
TemplateData() map[string]interface{}
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ require (
github.com/hashicorp/go-hclog v0.14.1
github.com/hashicorp/go-plugin v1.3.0
github.com/hashicorp/hcl/v2 v2.6.0
github.com/iancoleman/strcase v0.1.2
github.com/lab47/vterm v0.0.0-20201001232628-a9dd795f94c2
github.com/mattn/go-colorable v0.1.8
github.com/mattn/go-isatty v0.0.12
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ github.com/hashicorp/hcl/v2 v2.6.0 h1:3krZOfGY6SziUXa6H9PJU6TyohHn7I+ARYnhbeNBz+
github.com/hashicorp/hcl/v2 v2.6.0/go.mod h1:bQTN5mpo+jewjJgh8jr0JUguIi7qPHUF6yIfAEN3jqY=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/iancoleman/strcase v0.1.2 h1:gnomlvw9tnV3ITTAxzKSgTF+8kFWcU/f+TgttpXGz1U=
github.com/iancoleman/strcase v0.1.2/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE=
github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
Expand Down
19 changes: 18 additions & 1 deletion internal/plugin/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package plugin

import (
"context"
"encoding/json"

"github.com/golang/protobuf/ptypes/empty"
"github.com/hashicorp/go-argmapper"
Expand Down Expand Up @@ -135,8 +136,19 @@ func (c *builderClient) build(
return nil, err
}

var tplData map[string]interface{}
if len(resp.TemplateData) > 0 {
if err := json.Unmarshal(resp.TemplateData, &tplData); err != nil {
return nil, err
}
}

// We return the
mitchellh marked this conversation as resolved.
Show resolved Hide resolved
return &plugincomponent.Artifact{Any: resp.Result, LabelsVal: resp.Labels}, nil
return &plugincomponent.Artifact{
Any: resp.Result,
LabelsVal: resp.Labels,
TemplateVal: tplData,
}, nil
}

// builderServer is a gRPC server that the client talks to and calls a
Expand Down Expand Up @@ -206,6 +218,11 @@ func (s *builderServer) Build(
result.Labels = artifact.Labels()
}

result.TemplateData, err = templateData(raw)
if err != nil {
return nil, err
}

return result, nil
}

Expand Down
23 changes: 20 additions & 3 deletions internal/plugin/platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package plugin

import (
"context"
"encoding/json"
"reflect"

"github.com/davecgh/go-spew/spew"
Expand Down Expand Up @@ -239,7 +240,17 @@ func (c *platformClient) deploy(
return nil, err
}

return &plugincomponent.Deployment{Any: resp.Result}, nil
var tplData map[string]interface{}
if len(resp.TemplateData) > 0 {
if err := json.Unmarshal(resp.TemplateData, &tplData); err != nil {
return nil, err
}
}

return &plugincomponent.Deployment{
Any: resp.Result,
TemplateVal: tplData,
}, nil
}

func (c *platformClient) DefaultReleaserFunc() interface{} {
Expand Down Expand Up @@ -362,7 +373,7 @@ func (s *platformServer) Deploy(
internal := s.internal()
defer internal.Cleanup.Close()

encoded, _, err := callDynamicFuncAny2(s.Impl.DeployFunc(), args.Args,
encoded, raw, err := callDynamicFuncAny2(s.Impl.DeployFunc(), args.Args,
argmapper.ConverterFunc(s.Mappers...),
argmapper.Typed(internal),
argmapper.Typed(ctx),
Expand All @@ -371,7 +382,13 @@ func (s *platformServer) Deploy(
return nil, err
}

return &proto.Deploy_Resp{Result: encoded}, nil
result := &proto.Deploy_Resp{Result: encoded}
result.TemplateData, err = templateData(raw)
if err != nil {
return nil, err
}

return result, nil
}

func (s *platformServer) DefaultReleaserSpec(
Expand Down
24 changes: 20 additions & 4 deletions internal/plugin/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package plugin

import (
"context"
"encoding/json"

"github.com/golang/protobuf/ptypes/empty"
"github.com/hashicorp/go-argmapper"
Expand Down Expand Up @@ -134,8 +135,17 @@ func (c *registryClient) push(
return nil, err
}

// We return the *any.Any directly.
return &plugincomponent.Artifact{Any: resp.Result}, nil
var tplData map[string]interface{}
if len(resp.TemplateData) > 0 {
if err := json.Unmarshal(resp.TemplateData, &tplData); err != nil {
return nil, err
}
}

return &plugincomponent.Artifact{
Any: resp.Result,
TemplateVal: tplData,
}, nil
}

// registryServer is a gRPC server that the client talks to and calls a
Expand Down Expand Up @@ -190,7 +200,7 @@ func (s *registryServer) Push(
internal := s.internal()
defer internal.Cleanup.Close()

encoded, _, err := callDynamicFuncAny2(s.Impl.PushFunc(), args.Args,
encoded, raw, err := callDynamicFuncAny2(s.Impl.PushFunc(), args.Args,
argmapper.ConverterFunc(s.Mappers...),
argmapper.Logger(s.Logger),
argmapper.Typed(ctx),
Expand All @@ -200,7 +210,13 @@ func (s *registryServer) Push(
return nil, err
}

return &proto.Push_Resp{Result: encoded}, nil
result := &proto.Push_Resp{Result: encoded}
result.TemplateData, err = templateData(raw)
if err != nil {
return nil, err
}

return result, nil
}

var (
Expand Down
24 changes: 20 additions & 4 deletions internal/plugin/releaser.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package plugin

import (
"context"
"encoding/json"

"github.com/golang/protobuf/ptypes/empty"
"github.com/hashicorp/go-argmapper"
Expand Down Expand Up @@ -181,10 +182,18 @@ func (c *releaseManagerClient) build(
return nil, err
}

var tplData map[string]interface{}
if len(resp.TemplateData) > 0 {
if err := json.Unmarshal(resp.TemplateData, &tplData); err != nil {
return nil, err
}
}

// We return the
mitchellh marked this conversation as resolved.
Show resolved Hide resolved
return &plugincomponent.Release{
Any: resp.Result,
Release: resp.Release,
Any: resp.Result,
Release: resp.Release,
TemplateVal: tplData,
}, nil
}

Expand Down Expand Up @@ -257,12 +266,19 @@ func (s *releaseManagerServer) Release(
}

release := raw.(component.Release)
return &proto.Release_Resp{
result := &proto.Release_Resp{
Result: encoded,
Release: &proto.Release{
Url: release.URL(),
},
}, nil
}

result.TemplateData, err = templateData(raw)
if err != nil {
return nil, err
}

return result, nil
}

var (
Expand Down
88 changes: 88 additions & 0 deletions internal/plugin/template.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package plugin

import (
"encoding/json"
"reflect"
"strings"

"github.com/iancoleman/strcase"
"github.com/mitchellh/mapstructure"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

"github.com/hashicorp/waypoint-plugin-sdk/component"
)

// templateData returns the template data for a result object. If v
// implements component.Template that value is used. Otherwise, we automatically
// infer the fields based on the exported fields of the struct.
func templateData(v interface{}) ([]byte, error) {
// Determine our data
var data map[string]interface{}
if tpl, ok := v.(component.Template); ok {
data = tpl.TemplateData()
} else {
data = templateDataFromConfig(v)
}

// If empty we don't do anything
if len(data) == 0 {
return nil, nil
}

// Encode as JSON
encoded, err := json.Marshal(data)
if err != nil {
return nil, status.Errorf(codes.Aborted,
"failed to JSON encode result template data: %s", err)
}

return encoded, nil
}

func templateDataFromConfig(v interface{}) map[string]interface{} {
var result map[string]interface{}
dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
Result: &result,
DecodeHook: func(srcT, dstT reflect.Type, raw interface{}) (interface{}, error) {
for srcT.Kind() == reflect.Ptr {
srcT = srcT.Elem()
}
if srcT.Kind() != reflect.Struct {
return raw, nil
}

val := reflect.ValueOf(raw)
for val.Kind() == reflect.Ptr {
val = val.Elem()
}

m := map[string]interface{}{}
for i := 0; i < srcT.NumField(); i++ {
sf := srcT.Field(i)
if sf.PkgPath != "" {
// ignore unexported fields
continue
}

if strings.HasPrefix(sf.Name, "XXX_") {
// ignore proto internals
continue
}

name := strcase.ToSnake(sf.Name)
m[name] = val.Field(i).Interface()
}

return m, nil
},
})
if err != nil {
panic(err)
}
if err := dec.Decode(v); err != nil {
panic(err)
}

return result
}
71 changes: 71 additions & 0 deletions internal/plugin/template_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package plugin

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestTemplateDataFromConfig(t *testing.T) {
cases := []struct {
Name string
Input interface{}
Output map[string]interface{}
}{
{
"all-in-one",
struct {
Name string
Port int
ImageName string
}{
Name: "Hello",
Port: 80,
ImageName: "foo",
},
map[string]interface{}{
"name": "Hello",
"port": 80,
"image_name": "foo",
},
},

{
"pointer",
&struct {
Name string
Port int
}{
Name: "Hello",
Port: 80,
},
map[string]interface{}{
"name": "Hello",
"port": 80,
},
},

{
"protobuf fields",
&struct {
Name string
XXX_Hello string
}{
Name: "Hello",
XXX_Hello: "hi",
},
map[string]interface{}{
"name": "Hello",
},
},
}

for _, tt := range cases {
t.Run(tt.Name, func(t *testing.T) {
require := require.New(t)

v := templateDataFromConfig(tt.Input)
require.Equal(tt.Output, v)
})
}
}
Loading