feat: Allow hide resources (#3977)

This commit is contained in:
Bruno Quaresma
2022-09-09 16:38:00 -03:00
committed by GitHub
parent f6aa025a01
commit 8a94b72c7d
44 changed files with 458 additions and 335 deletions

View File

@ -36,6 +36,7 @@ type agentAppAttributes struct {
// A mapping of attributes on the "coder_metadata" resource.
type metadataAttributes struct {
ResourceID string `mapstructure:"resource_id"`
Hide bool `mapstructure:"hide"`
Items []metadataItem `mapstructure:"item"`
}
@ -48,6 +49,7 @@ type metadataItem struct {
// ConvertResources consumes Terraform state and a GraphViz representation produced by
// `terraform graph` to produce resources consumable by Coder.
// nolint:gocyclo
func ConvertResources(module *tfjson.StateModule, rawGraph string) ([]*proto.Resource, error) {
parsedGraph, err := gographviz.ParseString(rawGraph)
if err != nil {
@ -137,7 +139,7 @@ func ConvertResources(module *tfjson.StateModule, rawGraph string) ([]*proto.Res
}
var agentResource *graphResource
for _, resource := range findResourcesUpGraph(graph, tfResourceByLabel, agentNode.Name, 0) {
for _, resource := range findResourcesInGraph(graph, tfResourceByLabel, agentNode.Name, 0, true) {
if agentResource == nil {
// Default to the first resource because we have nothing to compare!
agentResource = resource
@ -234,7 +236,8 @@ func ConvertResources(module *tfjson.StateModule, rawGraph string) ([]*proto.Res
// Associate metadata blocks with resources.
resourceMetadata := map[string][]*proto.Resource_Metadata{}
for label, resource := range tfResourceByLabel {
resourceHidden := map[string]bool{}
for _, resource := range tfResourceByLabel {
if resource.Type != "coder_metadata" {
continue
}
@ -244,17 +247,54 @@ func ConvertResources(module *tfjson.StateModule, rawGraph string) ([]*proto.Res
return nil, xerrors.Errorf("decode metadata attributes: %w", err)
}
var targetLabel string
// This occurs in a plan, because there is no resource ID.
// We attempt to find the closest node, just so we can hide it from the UI.
if attrs.ResourceID == "" {
// TODO: detect this as an error
// At plan time, change.after_unknown.resource_id should be "true".
// At provision time, values.resource_id should be set.
resourceLabel := convertAddressToLabel(resource.Address)
var attachedNode *gographviz.Node
for _, node := range graph.Nodes.Lookup {
// The node attributes surround the label with quotes.
if strings.Trim(node.Attrs["label"], `"`) != resourceLabel {
continue
}
attachedNode = node
break
}
if attachedNode == nil {
continue
}
var attachedResource *graphResource
for _, resource := range findResourcesInGraph(graph, tfResourceByLabel, attachedNode.Name, 0, false) {
if attachedResource == nil {
// Default to the first resource because we have nothing to compare!
attachedResource = resource
continue
}
if resource.Depth < attachedResource.Depth {
// There's a closer resource!
attachedResource = resource
continue
}
if resource.Depth == attachedResource.Depth && resource.Label < attachedResource.Label {
attachedResource = resource
continue
}
}
if attachedResource == nil {
continue
}
targetLabel = attachedResource.Label
}
if targetLabel == "" {
targetLabel = resourceLabelByID[attrs.ResourceID]
}
if targetLabel == "" {
continue
}
targetLabel, ok := resourceLabelByID[attrs.ResourceID]
if !ok {
return nil, xerrors.Errorf("attribute %s.resource_id = %q does not refer to a valid resource", label, attrs.ResourceID)
}
resourceHidden[targetLabel] = attrs.Hide
for _, item := range attrs.Items {
resourceMetadata[targetLabel] = append(resourceMetadata[targetLabel],
&proto.Resource_Metadata{
@ -284,6 +324,7 @@ func ConvertResources(module *tfjson.StateModule, rawGraph string) ([]*proto.Res
Name: resource.Name,
Type: resource.Type,
Agents: agents,
Hide: resourceHidden[label],
Metadata: resourceMetadata[label],
})
}
@ -344,14 +385,19 @@ func applyAutomaticInstanceID(resource *tfjson.StateResource, agents []*proto.Ag
}
}
// findResourcesUpGraph traverses upwards in a graph until a resource is found,
// findResourcesInGraph traverses directionally in a graph until a resource is found,
// then it stores the depth it was found at, and continues working up the tree.
func findResourcesUpGraph(graph *gographviz.Graph, tfResourceByLabel map[string]*tfjson.StateResource, nodeName string, currentDepth uint) []*graphResource {
// nolint:revive
func findResourcesInGraph(graph *gographviz.Graph, tfResourceByLabel map[string]*tfjson.StateResource, nodeName string, currentDepth uint, up bool) []*graphResource {
graphResources := make([]*graphResource, 0)
for destination := range graph.Edges.DstToSrcs[nodeName] {
mapping := graph.Edges.DstToSrcs
if !up {
mapping = graph.Edges.SrcToDsts
}
for destination := range mapping[nodeName] {
destinationNode := graph.Nodes.Lookup[destination]
// Work our way up the tree!
graphResources = append(graphResources, findResourcesUpGraph(graph, tfResourceByLabel, destinationNode.Name, currentDepth+1)...)
graphResources = append(graphResources, findResourcesInGraph(graph, tfResourceByLabel, destinationNode.Name, currentDepth+1, up)...)
destinationLabel, exists := destinationNode.Attrs["label"]
if !exists {