Files
steampipe/pkg/steampipeconfig/parse/validate.go

125 lines
4.3 KiB
Go

package parse
import (
"fmt"
"github.com/hashicorp/hcl/v2"
"github.com/turbot/steampipe/pkg/steampipeconfig/modconfig"
)
// validate the resource
func validateResource(resource modconfig.HclResource) hcl.Diagnostics {
var diags hcl.Diagnostics
if qp, ok := resource.(modconfig.NodeAndEdgeProvider); ok {
moreDiags := validateNodeAndEdgeProvider(qp)
diags = append(diags, moreDiags...)
} else if qp, ok := resource.(modconfig.QueryProvider); ok {
moreDiags := validateQueryProvider(qp)
diags = append(diags, moreDiags...)
}
if wp, ok := resource.(modconfig.WithProvider); ok {
moreDiags := validateRuntimeDependencyProvider(wp)
diags = append(diags, moreDiags...)
}
return diags
}
func validateRuntimeDependencyProvider(wp modconfig.WithProvider) hcl.Diagnostics {
resource := wp.(modconfig.HclResource)
var diags hcl.Diagnostics
if len(wp.GetWiths()) > 0 && !resource.IsTopLevel() {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Only top level resources can have `with` blocks",
Detail: fmt.Sprintf("%s contains 'with' blocks but is not a top level resource.", resource.Name()),
Subject: resource.GetDeclRange(),
})
}
return diags
}
// validate that the provider does not contains both edges/nodes and a query/sql
// enrich the loaded nodes and edges with the fully parsed resources from the resourceMapProvider
func validateNodeAndEdgeProvider(resource modconfig.NodeAndEdgeProvider) hcl.Diagnostics {
// TODO [node_reuse] add NodeAndEdgeProviderImpl and move validate there
// https://github.com/turbot/steampipe/issues/2918
var diags hcl.Diagnostics
containsEdgesOrNodes := len(resource.GetEdges())+len(resource.GetNodes()) > 0
definesQuery := resource.GetSQL() != nil || resource.GetQuery() != nil
// cannot declare both edges/nodes AND sql/query
if definesQuery && containsEdgesOrNodes {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: fmt.Sprintf("%s contains edges/nodes AND has a query", resource.Name()),
Subject: resource.GetDeclRange(),
})
}
// if resource is NOT top level must have either edges/nodes OR sql/query
if !resource.IsTopLevel() && !definesQuery && !containsEdgesOrNodes {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: fmt.Sprintf("%s does not define a query or SQL, and has no edges/nodes", resource.Name()),
Subject: resource.GetDeclRange(),
})
}
diags = append(diags, validateSqlAndQueryNotBothSet(resource)...)
diags = append(diags, validateParamAndQueryNotBothSet(resource)...)
return diags
}
func validateQueryProvider(resource modconfig.QueryProvider) hcl.Diagnostics {
var diags hcl.Diagnostics
diags = append(diags, resource.ValidateQuery()...)
diags = append(diags, validateSqlAndQueryNotBothSet(resource)...)
diags = append(diags, validateParamAndQueryNotBothSet(resource)...)
return diags
}
func validateParamAndQueryNotBothSet(resource modconfig.QueryProvider) hcl.Diagnostics {
var diags hcl.Diagnostics
// param block cannot be set if a query property is set - it is only valid if inline SQL ids defined
if len(resource.GetParams()) > 0 {
if resource.GetQuery() != nil {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagWarning,
Summary: fmt.Sprintf("Deprecated usage: %s has 'query' property set so should not define 'param' blocks", resource.Name()),
Subject: resource.GetDeclRange(),
})
}
if !resource.IsTopLevel() && !resource.ParamsInheritedFromBase() {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagWarning,
Summary: "Deprecated usage: Only top level resources can have 'param' blocks",
Detail: fmt.Sprintf("%s contains 'param' blocks but is not a top level resource.", resource.Name()),
Subject: resource.GetDeclRange(),
})
}
}
return diags
}
func validateSqlAndQueryNotBothSet(resource modconfig.QueryProvider) hcl.Diagnostics {
var diags hcl.Diagnostics
// are both sql and query set?
if resource.GetSQL() != nil && resource.GetQuery() != nil {
// either Query or SQL property may be set - if Query property already set, error
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: fmt.Sprintf("%s has both 'SQL' and 'query' property set - only 1 of these may be set", resource.Name()),
Subject: resource.GetDeclRange(),
})
}
return diags
}