github.com/turbot/steampipe@v1.7.0-rc.0.0.20240517123944-7cef272d4458/pkg/steampipeconfig/parse/validate.go (about) 1 package parse 2 3 import ( 4 "fmt" 5 "github.com/hashicorp/hcl/v2" 6 "github.com/turbot/steampipe/pkg/steampipeconfig/modconfig" 7 ) 8 9 // validate the resource 10 func validateResource(resource modconfig.HclResource) hcl.Diagnostics { 11 var diags hcl.Diagnostics 12 if qp, ok := resource.(modconfig.NodeAndEdgeProvider); ok { 13 moreDiags := validateNodeAndEdgeProvider(qp) 14 diags = append(diags, moreDiags...) 15 } else if qp, ok := resource.(modconfig.QueryProvider); ok { 16 moreDiags := validateQueryProvider(qp) 17 diags = append(diags, moreDiags...) 18 } 19 20 if wp, ok := resource.(modconfig.WithProvider); ok { 21 moreDiags := validateRuntimeDependencyProvider(wp) 22 diags = append(diags, moreDiags...) 23 } 24 return diags 25 } 26 27 func validateRuntimeDependencyProvider(wp modconfig.WithProvider) hcl.Diagnostics { 28 resource := wp.(modconfig.HclResource) 29 var diags hcl.Diagnostics 30 if len(wp.GetWiths()) > 0 && !resource.IsTopLevel() { 31 diags = append(diags, &hcl.Diagnostic{ 32 Severity: hcl.DiagError, 33 Summary: "Only top level resources can have `with` blocks", 34 Detail: fmt.Sprintf("%s contains 'with' blocks but is not a top level resource.", resource.Name()), 35 Subject: resource.GetDeclRange(), 36 }) 37 } 38 return diags 39 } 40 41 // validate that the provider does not contains both edges/nodes and a query/sql 42 // enrich the loaded nodes and edges with the fully parsed resources from the resourceMapProvider 43 func validateNodeAndEdgeProvider(resource modconfig.NodeAndEdgeProvider) hcl.Diagnostics { 44 // TODO [node_reuse] add NodeAndEdgeProviderImpl and move validate there 45 // https://github.com/turbot/steampipe/issues/2918 46 47 var diags hcl.Diagnostics 48 containsEdgesOrNodes := len(resource.GetEdges())+len(resource.GetNodes()) > 0 49 definesQuery := resource.GetSQL() != nil || resource.GetQuery() != nil 50 51 // cannot declare both edges/nodes AND sql/query 52 if definesQuery && containsEdgesOrNodes { 53 diags = append(diags, &hcl.Diagnostic{ 54 Severity: hcl.DiagError, 55 Summary: fmt.Sprintf("%s contains edges/nodes AND has a query", resource.Name()), 56 Subject: resource.GetDeclRange(), 57 }) 58 } 59 60 // if resource is NOT top level must have either edges/nodes OR sql/query 61 if !resource.IsTopLevel() && !definesQuery && !containsEdgesOrNodes { 62 diags = append(diags, &hcl.Diagnostic{ 63 Severity: hcl.DiagError, 64 Summary: fmt.Sprintf("%s does not define a query or SQL, and has no edges/nodes", resource.Name()), 65 Subject: resource.GetDeclRange(), 66 }) 67 } 68 69 diags = append(diags, validateSqlAndQueryNotBothSet(resource)...) 70 71 diags = append(diags, validateParamAndQueryNotBothSet(resource)...) 72 73 return diags 74 } 75 76 func validateQueryProvider(resource modconfig.QueryProvider) hcl.Diagnostics { 77 var diags hcl.Diagnostics 78 79 diags = append(diags, resource.ValidateQuery()...) 80 81 diags = append(diags, validateSqlAndQueryNotBothSet(resource)...) 82 83 diags = append(diags, validateParamAndQueryNotBothSet(resource)...) 84 85 return diags 86 } 87 88 func validateParamAndQueryNotBothSet(resource modconfig.QueryProvider) hcl.Diagnostics { 89 var diags hcl.Diagnostics 90 91 // param block cannot be set if a query property is set - it is only valid if inline SQL ids defined 92 if len(resource.GetParams()) > 0 { 93 if resource.GetQuery() != nil { 94 diags = append(diags, &hcl.Diagnostic{ 95 Severity: hcl.DiagWarning, 96 Summary: fmt.Sprintf("Deprecated usage: %s has 'query' property set so should not define 'param' blocks", resource.Name()), 97 Subject: resource.GetDeclRange(), 98 }) 99 } 100 if !resource.IsTopLevel() && !resource.ParamsInheritedFromBase() { 101 diags = append(diags, &hcl.Diagnostic{ 102 Severity: hcl.DiagWarning, 103 Summary: "Deprecated usage: Only top level resources can have 'param' blocks", 104 Detail: fmt.Sprintf("%s contains 'param' blocks but is not a top level resource.", resource.Name()), 105 Subject: resource.GetDeclRange(), 106 }) 107 } 108 } 109 return diags 110 } 111 112 func validateSqlAndQueryNotBothSet(resource modconfig.QueryProvider) hcl.Diagnostics { 113 var diags hcl.Diagnostics 114 // are both sql and query set? 115 if resource.GetSQL() != nil && resource.GetQuery() != nil { 116 // either Query or SQL property may be set - if Query property already set, error 117 diags = append(diags, &hcl.Diagnostic{ 118 Severity: hcl.DiagError, 119 Summary: fmt.Sprintf("%s has both 'SQL' and 'query' property set - only 1 of these may be set", resource.Name()), 120 Subject: resource.GetDeclRange(), 121 }) 122 } 123 return diags 124 }