asteris-llc/converge

View on GitHub
prettyprinters/graphviz/providers/rpc.go

Summary

Maintainability
A
55 mins
Test Coverage
// 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{}
}