prettyprinters/graphviz/providers/rpc.go
// Copyright © 2016 Asteris, LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package providers
import (
"encoding/json"
"fmt"
"strings"
pp "github.com/asteris-llc/converge/prettyprinters"
"github.com/asteris-llc/converge/prettyprinters/graphviz"
"github.com/asteris-llc/converge/resource/file/content"
"github.com/asteris-llc/converge/resource/file/directory"
"github.com/asteris-llc/converge/resource/param"
"github.com/asteris-llc/converge/resource/wait/port"
"github.com/asteris-llc/converge/rpc/pb"
"github.com/pkg/errors"
)
// RPCProvider is the PrintProvider type for Resources
type RPCProvider struct {
graphviz.GraphIDProvider
ShowParams bool
}
// VertexGetID returns the graph ID as the VertexID, possibly maksing it
// depending on the vertext type and configuration.
func (p RPCProvider) VertexGetID(e graphviz.GraphEntity) (pp.VisibleRenderable, error) {
val, ok := e.Value.(*pb.GraphComponent_Vertex)
if !ok {
return pp.VisibleString(e.Name), nil
}
switch val.Kind {
case "param":
return pp.RenderableString(e.Name, p.ShowParams), nil
default:
return pp.VisibleString(e.Name), nil
}
}
// VertexGetLabel returns a vertext label based on the type of the resource. The
// specific generated labels sare:
// Templates: Return 'Template' and the file destination
// Modules: Return 'Module' and the module name
// Params: Return 'name -> "value"'
// otherwise: Return 'name'
func (p RPCProvider) VertexGetLabel(e graphviz.GraphEntity) (pp.VisibleRenderable, error) {
var name string
if e.Name == rootNodeID {
name = "/"
} else {
parts := strings.Split(e.Name, "/")
name = parts[len(parts)-1]
}
val, ok := e.Value.(*pb.GraphComponent_Vertex)
if !ok {
return pp.VisibleString(name), nil
}
switch val.Kind {
case "file.content":
var dest = new(content.Content)
if err := json.Unmarshal(val.Details, dest); err != nil {
return nil, errors.Wrap(err, "could not unmarshal file content")
}
return pp.VisibleString(fmt.Sprintf("File: %s", dest.Destination)), nil
case "file.directory":
var dest = new(directory.Directory)
if err := json.Unmarshal(val.Details, dest); err != nil {
return nil, errors.Wrap(err, "could not unmarshal directory")
}
return pp.VisibleString(fmt.Sprintf("Directory: %s", dest.Destination)), nil
case "module":
return pp.VisibleString(fmt.Sprintf("Module: %s", name)), nil
case "param":
var dest = new(param.Param)
if err := json.Unmarshal(val.Details, dest); err != nil {
return nil, errors.Wrap(err, "could not unmarshal param")
}
return pp.RenderableString(
fmt.Sprintf("%s: %s", name, dest.Val),
p.ShowParams,
), nil
case "docker.image":
return dockerImageLabel(val)
case "docker.container":
return dockerContainerLabel(val)
case "wait.port":
var dest = new(port.Port)
if err := json.Unmarshal(val.Details, dest); err != nil {
return nil, errors.Wrap(err, "could not unmarshal docker port")
}
return pp.VisibleString(fmt.Sprintf("Wait: %s:%d", dest.Host, dest.Port)), nil
default:
return pp.VisibleString(name), nil
}
}
// VertexGetProperties sets graphviz attributes based on the type of the
// resource. Specifically, we set the shape to 'component' for Shell preparers
// and 'tab' for templates, and we set the entire root node to be invisible.
func (p RPCProvider) VertexGetProperties(e graphviz.GraphEntity) graphviz.PropertySet {
properties := make(map[string]string)
val, ok := e.Value.(*pb.GraphComponent_Vertex)
if !ok {
return properties
}
switch val.Kind {
case "task":
properties["shape"] = "component"
case "file.content", "file.directory":
properties["shape"] = "tab"
case "module":
properties["shape"] = "folder"
case "docker.image", "docker.container":
properties["shape"] = "box3d"
}
return properties
}
// EdgeGetProperties sets attributes for graph edges, specifically making edges
// originating from the Root node invisible.
func (p RPCProvider) EdgeGetProperties(src graphviz.GraphEntity, dst graphviz.GraphEntity) graphviz.PropertySet {
properties := make(map[string]string)
return properties
}
// SubgraphMarker identifies the start of subgraphs for resources.
// Specifically, it starts a new subgraph whenever a new 'Module' type resource
// is encountered.
func (p RPCProvider) SubgraphMarker(e graphviz.GraphEntity) graphviz.SubgraphMarkerKey {
val, ok := e.Value.(*pb.GraphComponent_Vertex)
if !ok {
return graphviz.SubgraphMarkerNOP
}
if val.Kind == "module" {
return graphviz.SubgraphMarkerStart
}
return graphviz.SubgraphMarkerNOP
}
// NewRPCProvider is a utility function to return a new RPCProvider
func NewRPCProvider() graphviz.PrintProvider {
return RPCProvider{}
}