Merge branch 'v0.21.x'

# Conflicts:
#	pkg/steampipeconfig/modconfig/mod.go
This commit is contained in:
kai
2024-02-06 11:47:32 +00:00
101 changed files with 1113 additions and 218 deletions

View File

@@ -328,6 +328,7 @@ jobs:
- "mod_vars"
- "mod"
- "mod_require"
- "pp_files"
- "check"
- "performance"
- "config_precedence"

View File

@@ -110,6 +110,7 @@ jobs:
- "mod_vars"
- "mod"
- "mod_require"
- "pp_files"
- "check"
- "performance"
- "config_precedence"

View File

@@ -1,3 +1,12 @@
## v0.21.6 [2024-02-06]
_Bug fixes_
* Fix `HomeDirectoryModfileCheck` returning false positive, causing errors when executing steampipe out of the home directory. ([#4118](https://github.com/turbot/steampipe/issues/4118))
## v0.21.5 [2024-02-05]
_Bug fixes_
* Fix dependency variable validation - was failing if dependency variable value was set in the vars file. ([#4110](https://github.com/turbot/steampipe/issues/4110))
* Fix UI freeze when prompting for workspace variables. ([#4105](https://github.com/turbot/steampipe/issues/4105))
## v0.21.4 [2024-01-23]
_Bug fixes_
* Fixed schema clone function failing if table has an LTREE column. ([#4079](https://github.com/turbot/steampipe/issues/4079))

View File

@@ -317,6 +317,7 @@ func validateCheckArgs(ctx context.Context, cmd *cobra.Command, args []string) b
fmt.Println()
error_helpers.ShowError(ctx, fmt.Errorf("you must provide at least one argument"))
fmt.Println()
//nolint:errcheck // cmd.Help always returns a nil error
cmd.Help()
fmt.Println()
return false

View File

@@ -6,9 +6,7 @@ import (
"sort"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/turbot/steampipe/pkg/cmdconfig"
"github.com/turbot/steampipe/pkg/constants"
"github.com/turbot/steampipe/pkg/display"
"github.com/turbot/steampipe/pkg/error_helpers"
"github.com/turbot/steampipe/pkg/steampipeconfig/modconfig"
@@ -44,9 +42,10 @@ func getRunListSubCmd(opts listSubCmdOptions) func(cmd *cobra.Command, args []st
return func(cmd *cobra.Command, _ []string) {
ctx := cmd.Context()
workspacePath := viper.GetString(constants.ArgModLocation)
w, errAndWarnings := workspace.Load(ctx, workspacePath)
w, errAndWarnings := workspace.LoadWorkspaceVars(ctx)
error_helpers.FailOnError(errAndWarnings.GetError())
errAndWarnings = w.LoadWorkspaceMod(ctx)
error_helpers.FailOnError(errAndWarnings.GetError())
modResources, depResources, err := listResourcesInMod(ctx, w.Mod, cmd)

View File

@@ -343,7 +343,7 @@ func createWorkspaceMod(ctx context.Context, cmd *cobra.Command, workspacePath s
return nil, fmt.Errorf("mod %s cancelled", cmd.Name())
}
if parse.ModfileExists(workspacePath) {
if _, exists := parse.ModfileExists(workspacePath); exists {
fmt.Println("Working folder already contains a mod definition file")
return nil, nil
}
@@ -354,7 +354,7 @@ func createWorkspaceMod(ctx context.Context, cmd *cobra.Command, workspacePath s
}
// only print message for mod init (not for mod install)
if cmd.Name() == "init" {
fmt.Printf("Created mod definition file '%s'\n", filepaths.ModFilePath(workspacePath))
fmt.Printf("Created mod definition file '%s'\n", filepaths.DefaultModFilePath(workspacePath))
}
// load up the written mod file so that we get the updated

1
go.mod
View File

@@ -150,7 +150,6 @@ require (
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/compress v1.17.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect

View File

@@ -2,19 +2,19 @@ package constants
import "github.com/turbot/go-kit/helpers"
var ModDataExtensions = []string{".sp", "*.pp"}
var ModDataExtensions = []string{".sp", ".pp"}
var VariablesExtensions = []string{".spvars", ".ppvars"}
var AutoVariablesExtensions = []string{".auto.spvars", ".auto.ppvars"}
const (
PluginExtension = ".plugin"
ConfigExtension = ".spc"
SqlExtension = ".sql"
VariablesExtension = ".spvars"
AutoVariablesExtension = ".auto.spvars"
JsonExtension = ".json"
TextExtension = ".txt"
SnapshotExtension = ".sps"
TokenExtension = ".tptt"
LegacyTokenExtension = ".sptt"
PluginExtension = ".plugin"
ConfigExtension = ".spc"
SqlExtension = ".sql"
JsonExtension = ".json"
TextExtension = ".txt"
SnapshotExtension = ".sps"
TokenExtension = ".tptt"
LegacyTokenExtension = ".sptt"
)
var YamlExtensions = []string{".yml", ".yaml"}

View File

@@ -2,6 +2,7 @@ package dashboardexecute
import (
"context"
"github.com/turbot/steampipe/pkg/control/controlexecute"
"github.com/turbot/steampipe/pkg/control/controlstatus"
"github.com/turbot/steampipe/pkg/dashboard/dashboardtypes"
@@ -65,7 +66,10 @@ func (r *CheckRun) Execute(ctx context.Context) {
// create a context with a DashboardEventControlHooks to report control execution progress
ctx = controlstatus.AddControlHooksToContext(ctx, NewDashboardEventControlHooks(r))
r.controlExecutionTree.Execute(ctx)
if err := r.controlExecutionTree.Execute(ctx); err != nil {
r.SetError(ctx, err)
return
}
// set the summary on the CheckRun
r.Summary = r.controlExecutionTree.Root.Summary

View File

@@ -3,9 +3,10 @@ package dashboardexecute
import (
"context"
"fmt"
"log"
"github.com/turbot/steampipe/pkg/dashboard/dashboardtypes"
"github.com/turbot/steampipe/pkg/steampipeconfig/modconfig"
"log"
)
// DashboardContainerRun is a struct representing a container run
@@ -45,6 +46,7 @@ func NewDashboardContainerRun(container *modconfig.DashboardContainer, parent da
r.childCompleteChan = make(chan dashboardtypes.DashboardTreeRun, len(children))
for _, child := range children {
var childRun dashboardtypes.DashboardTreeRun
//nolint:golint // using a global var here to maintain parity with definition of childRun
var err error
switch i := child.(type) {
case *modconfig.DashboardContainer:

View File

@@ -2,10 +2,11 @@ package dashboardexecute
import (
"fmt"
"strings"
"github.com/turbot/steampipe/pkg/dashboard/dashboardtypes"
"github.com/turbot/steampipe/pkg/steampipeconfig/modconfig"
"github.com/turbot/steampipe/pkg/workspace"
"strings"
)
// GetReferencedVariables builds map of variables values containing only those mod variables which are referenced
@@ -35,6 +36,7 @@ func GetReferencedVariables(root dashboardtypes.DashboardTreeRun, w *workspace.W
switch r := root.(type) {
case *DashboardRun:
//nolint:errcheck // we don't care about errors here, since the callback does not return an error
r.dashboard.WalkResources(
func(resource modconfig.HclResource) (bool, error) {
if resourceWithMetadata, ok := resource.(modconfig.ResourceWithMetadata); ok {
@@ -46,6 +48,7 @@ func GetReferencedVariables(root dashboardtypes.DashboardTreeRun, w *workspace.W
case *CheckRun:
switch n := r.resource.(type) {
case *modconfig.Benchmark:
//nolint:errcheck // we don't care about errors here, since the callback does not return an error
n.WalkResources(
func(resource modconfig.ModTreeItem) (bool, error) {
if resourceWithMetadata, ok := resource.(modconfig.ResourceWithMetadata); ok {

View File

@@ -4,12 +4,13 @@ import (
"context"
"encoding/json"
"fmt"
"github.com/turbot/steampipe/pkg/dashboard/dashboardtypes"
"github.com/turbot/steampipe/pkg/steampipeconfig/modconfig"
"github.com/turbot/steampipe/pkg/utils"
"log"
"strconv"
"sync"
"github.com/turbot/steampipe/pkg/dashboard/dashboardtypes"
"github.com/turbot/steampipe/pkg/steampipeconfig/modconfig"
"github.com/turbot/steampipe/pkg/utils"
)
type runtimeDependencyPublisherImpl struct {
@@ -234,7 +235,6 @@ func (p *runtimeDependencyPublisherImpl) setWithValue(w *LeafRun) {
populateData(w.Data, result)
}
p.PublishRuntimeDependencyValue(name, result)
return
}
func populateData(withData *dashboardtypes.LeafData, result *dashboardtypes.ResolvedRuntimeDependencyValue) {

View File

@@ -361,6 +361,7 @@ func (s *RuntimeDependencySubscriberImpl) populateParamDefaults(provider modconf
if dep := s.findRuntimeDependencyForParentProperty(paramDef.UnqualifiedName); dep != nil {
// assuming the default property is the target, set the default
if typehelpers.SafeString(dep.Dependency.TargetPropertyName) == "default" {
//nolint:errcheck // the only reason where SetDefault could fail is if `dep.Value` cannot be marshalled as a JSON string
paramDef.SetDefault(dep.Value)
}
}

View File

@@ -31,7 +31,9 @@ func GenerateSnapshot(ctx context.Context, target string, initData *initialisati
// all runtime dependencies must be resolved before execution (i.e. inputs must be passed in)
Executor.interactive = false
Executor.ExecuteDashboard(ctx, sessionId, target, inputs, w, initData.Client)
if err := Executor.ExecuteDashboard(ctx, sessionId, target, inputs, w, initData.Client); err != nil {
return nil, err
}
select {
case err = <-errorChannel:

View File

@@ -9,6 +9,8 @@ import (
"github.com/turbot/steampipe/pkg/constants/runtime"
)
var ModFileNames = []string{"mod.sp", "mod.pp"}
// mod related constants
const (
WorkspaceDataDir = ".steampipe"
@@ -16,7 +18,6 @@ const (
WorkspaceModShadowDirPrefix = ".mods."
WorkspaceConfigFileName = "workspace.spc"
WorkspaceIgnoreFile = ".steampipeignore"
ModFileName = "mod.sp"
DefaultVarsFileName = "steampipe.spvars"
WorkspaceLockFileName = ".mod.cache.json"
)
@@ -41,7 +42,16 @@ func DefaultVarsFilePath(workspacePath string) string {
return path.Join(workspacePath, DefaultVarsFileName)
}
func ModFilePath(modFolder string) string {
modFilePath := filepath.Join(modFolder, ModFileName)
return modFilePath
func DefaultModFilePath(modFolder string) string {
return filepath.Join(modFolder, ModFileNames[0])
}
func ModFilePaths(modFolder string) []string {
var modFilePaths []string
for _, modFileName := range ModFileNames {
modFilePaths = append(modFilePaths, filepath.Join(modFolder, modFileName))
}
return modFilePaths
}

View File

@@ -6,7 +6,6 @@ import (
"os"
"github.com/hashicorp/hcl/v2/hclwrite"
"github.com/turbot/steampipe/pkg/filepaths"
"github.com/turbot/steampipe/pkg/steampipeconfig/modconfig"
"github.com/zclconf/go-cty/cty"
)
@@ -52,13 +51,13 @@ func (i *ModInstaller) updateModFile() error {
contents.ApplyChanges(changes)
contents.Apply(hclwrite.Format)
return os.WriteFile(filepaths.ModFilePath(i.workspaceMod.ModPath), contents.Bytes(), 0644)
return os.WriteFile(i.workspaceMod.FilePath(), contents.Bytes(), 0644)
}
// loads the contents of the mod.sp file and wraps it with a thin wrapper
// to assist in byte sequence manipulation
func (i *ModInstaller) loadModFileBytes() (*ByteSequence, error) {
modFileBytes, err := os.ReadFile(filepaths.ModFilePath(i.workspaceMod.ModPath))
modFileBytes, err := os.ReadFile(i.workspaceMod.FilePath())
if err != nil {
return nil, err
}

View File

@@ -51,8 +51,8 @@ func NewInitData(ctx context.Context, args []string) *InitData {
statushooks.SetStatus(ctx, "Loading workspace")
// load workspace syncronously
w, errAndWarnings := workspace.LoadWorkspacePromptingForVariables(ctx)
// load workspace variables syncronously
w, errAndWarnings := workspace.LoadWorkspaceVars(ctx)
if errAndWarnings.GetError() != nil {
i.Result.Error = fmt.Errorf("failed to load workspace: %s", error_helpers.HandleCancelError(errAndWarnings.GetError()).Error())
return i
@@ -115,6 +115,14 @@ func (i *InitData) init(ctx context.Context, args []string) {
}
}
// load the workspace mod (this load is asynchronous as it is within the async init function)
errAndWarnings := i.Workspace.LoadWorkspaceMod(ctx)
i.Result.AddWarnings(errAndWarnings.Warnings...)
if errAndWarnings.GetError() != nil {
i.Result.Error = fmt.Errorf("failed to load workspace mod: %s", error_helpers.HandleCancelError(errAndWarnings.GetError()).Error())
return
}
// set max DB connections to 1
viper.Set(constants.ArgMaxParallel, 1)

View File

@@ -326,5 +326,10 @@ func (v unparsedVariableValueString) ParseVariableValue(mode var_config.Variable
// isAutoVarFile determines if the file ends with .auto.spvars or .auto.spvars.json
func isAutoVarFile(path string) bool {
return strings.HasSuffix(path, constants.AutoVariablesExtension)
for _, ext := range constants.AutoVariablesExtensions {
if strings.HasSuffix(path, ext) {
return true
}
}
return false
}

View File

@@ -67,10 +67,11 @@ func loadModDefinition(ctx context.Context, modPath string, parseCtx *parse.ModP
return nil, error_helpers.NewErrorsAndWarning(fmt.Errorf("mod folder %s does not exist", modPath))
}
if parse.ModfileExists(modPath) {
modFilePath, exists := parse.ModfileExists(modPath)
if exists {
// load the mod definition to get the dependencies
var res *parse.DecodeResult
mod, res = parse.ParseModDefinition(modPath, parseCtx.EvalCtx)
mod, res = parse.ParseModDefinition(modFilePath, parseCtx.EvalCtx)
errorsAndWarnings = error_helpers.DiagsToErrorsAndWarnings("mod load failed", res.Diags)
if res.Diags.HasErrors() {
return nil, errorsAndWarnings
@@ -235,7 +236,7 @@ func LoadModResourceNames(ctx context.Context, mod *modconfig.Mod, parseCtx *par
// this will be the mod data extension, plus any registered extensions registered in fileToResourceMap
func GetModFileExtensions() []string {
res := append(modconfig.RegisteredFileExtensions(), constants.ModDataExtensions...)
return append(res, constants.VariablesExtension)
return append(res, constants.VariablesExtensions...)
}
// build list of all filepaths we need to parse/load the mod

View File

@@ -4,17 +4,16 @@ import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/Masterminds/semver/v3"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/hashicorp/hcl/v2/hclwrite"
filehelpers "github.com/turbot/go-kit/files"
typehelpers "github.com/turbot/go-kit/types"
"github.com/turbot/pipe-fittings/hclhelpers"
"github.com/turbot/steampipe/pkg/filepaths"
"github.com/zclconf/go-cty/cty"
)
// mod name used if a default mod is created for a workspace which does not define one explicitly
@@ -141,6 +140,10 @@ func (m *Mod) IsDefaultMod() bool {
return m.modFilePath == ""
}
func (m *Mod) FilePath() string {
return m.modFilePath
}
// GetPaths implements ModTreeItem (override base functionality)
func (m *Mod) GetPaths() []NodePath {
return []NodePath{{m.Name()}}
@@ -286,13 +289,7 @@ func (m *Mod) Save() error {
}
}
// load existing mod data and remove the mod definitions from it
nonModData, err := m.loadNonModDataInModFile()
if err != nil {
return err
}
modData := append(f.Bytes(), nonModData...)
return os.WriteFile(filepaths.ModFilePath(m.ModPath), modData, 0644)
return os.WriteFile(filepaths.DefaultModFilePath(m.ModPath), f.Bytes(), 0644)
}
func (m *Mod) HasDependentMods() bool {
@@ -306,32 +303,6 @@ func (m *Mod) GetModDependency(modName string) *ModVersionConstraint {
return m.Require.GetModDependency(modName)
}
func (m *Mod) loadNonModDataInModFile() ([]byte, error) {
modFilePath := filepaths.ModFilePath(m.ModPath)
if !filehelpers.FileExists(modFilePath) {
return nil, nil
}
fileData, err := os.ReadFile(modFilePath)
if err != nil {
return nil, err
}
fileLines := strings.Split(string(fileData), "\n")
decl := m.DeclRange
// just use line positions
start := decl.Start.Line - 1
end := decl.End.Line - 1
var resLines []string
for i, line := range fileLines {
if (i < start || i > end) && line != "" {
resLines = append(resLines, line)
}
}
return []byte(strings.Join(resLines, "\n")), nil
}
func (m *Mod) WalkResources(resourceFunc func(item HclResource) (bool, error)) error {
return m.ResourceMaps.WalkResources(resourceFunc)
}
@@ -410,3 +381,12 @@ func (m *Mod) RequireHasUnresolvedArgs() bool {
}
return false
}
func (m *Mod) hasChild(item ModTreeItem) bool {
for _, c := range m.children {
if c == item {
return true
}
}
return false
}

View File

@@ -47,6 +47,13 @@ func (m *Mod) addResourcesIntoTree(sourceMod *Mod) error {
resourceFunc := func(item HclResource) (bool, error) {
if treeItem, ok := item.(ModTreeItem); ok {
// TACTICAL: addResourcesIntoTree getc called severasl times, as we parse the mod in stages
// - first the variables then the rest of the resources
// if we have already added this into the tree, skip
if m.hasChild(treeItem) {
return true, nil
}
// NOTE: add resource into _our_ resource tree, i.e. mod 'm'
if err = m.addItemIntoResourceTree(treeItem); err != nil {
// stop walking

View File

@@ -11,13 +11,13 @@ import (
"github.com/turbot/pipe-fittings/hclhelpers"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin"
"github.com/turbot/steampipe/pkg/error_helpers"
"github.com/turbot/steampipe/pkg/filepaths"
"github.com/turbot/steampipe/pkg/steampipeconfig/modconfig"
"github.com/zclconf/go-cty/cty"
)
func LoadModfile(modPath string) (*modconfig.Mod, error) {
if !ModfileExists(modPath) {
modFilePath, exists := ModfileExists(modPath)
if !exists {
return nil, nil
}
@@ -27,7 +27,7 @@ func LoadModfile(modPath string) (*modconfig.Mod, error) {
Variables: make(map[string]cty.Value),
}
mod, res := ParseModDefinition(modPath, evalCtx)
mod, res := ParseModDefinition(modFilePath, evalCtx)
if res.Diags.HasErrors() {
return nil, plugin.DiagsToError("Failed to load mod", res.Diags)
}
@@ -38,15 +38,14 @@ func LoadModfile(modPath string) (*modconfig.Mod, error) {
// ParseModDefinition parses the modfile only
// it is expected the calling code will have verified the existence of the modfile by calling ModfileExists
// this is called before parsing the workspace to, for example, identify dependency mods
func ParseModDefinition(modPath string, evalCtx *hcl.EvalContext) (*modconfig.Mod, *DecodeResult) {
func ParseModDefinition(modFilePath string, evalCtx *hcl.EvalContext) (*modconfig.Mod, *DecodeResult) {
res := newDecodeResult()
// if there is no mod at this location, return error
modFilePath := filepaths.ModFilePath(modPath)
if _, err := os.Stat(modFilePath); os.IsNotExist(err) {
res.Diags = append(res.Diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: fmt.Sprintf("no mod file found in %s", modPath),
Summary: fmt.Sprintf("modfile %s does not exist", modFilePath),
})
return nil, res
}
@@ -73,7 +72,7 @@ func ParseModDefinition(modPath string, evalCtx *hcl.EvalContext) (*modconfig.Mo
if block == nil {
res.Diags = append(res.Diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: fmt.Sprintf("failed to parse mod definition file: no mod definition found in %s", fmt.Sprintf("%s/mod.sp", modPath)),
Summary: fmt.Sprintf("failed to parse mod definition file: no mod definition found in %s", modFilePath),
})
return nil, res
}

View File

@@ -2,6 +2,7 @@ package parse
import (
"fmt"
"github.com/turbot/steampipe/pkg/filepaths"
"io"
"log"
"os"
@@ -81,13 +82,14 @@ func buildOrderedFileNameList(fileData map[string][]byte) []string {
return filePaths
}
// ModfileExists returns whether a mod file exists at the specified path
func ModfileExists(modPath string) bool {
modFilePath := filepath.Join(modPath, "mod.sp")
if _, err := os.Stat(modFilePath); os.IsNotExist(err) {
return false
// ModfileExists returns whether a mod file exists at the specified path and if so returns the filepath
func ModfileExists(modPath string) (string, bool) {
for _, modFilePath := range filepaths.ModFilePaths(modPath) {
if _, err := os.Stat(modFilePath); err == nil {
return modFilePath, true
}
}
return true
return "", false
}
// parse a yaml file into a hcl.File object

View File

@@ -18,7 +18,7 @@ Also https://www.digitalocean.com/community/tutorials/using-ldflags-to-set-versi
**/
// The main version number that is being run at the moment.
var steampipeVersion = "0.21.4"
var steampipeVersion = "0.21.6"
// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release

View File

@@ -2,7 +2,6 @@ package workspace
import (
"context"
"errors"
"fmt"
"log"
"time"
@@ -10,47 +9,24 @@ import (
"github.com/spf13/viper"
"github.com/turbot/steampipe/pkg/constants"
"github.com/turbot/steampipe/pkg/error_helpers"
"github.com/turbot/steampipe/pkg/statushooks"
"github.com/turbot/steampipe/pkg/steampipeconfig"
"github.com/turbot/steampipe/pkg/steampipeconfig/inputvars"
"github.com/turbot/steampipe/pkg/steampipeconfig/modconfig"
"github.com/turbot/terraform-components/terraform"
)
func LoadWorkspacePromptingForVariables(ctx context.Context) (*Workspace, *error_helpers.ErrorAndWarnings) {
workspacePath := viper.GetString(constants.ArgModLocation)
t := time.Now()
defer func() {
log.Printf("[TRACE] Workspace load took %dms\n", time.Since(t).Milliseconds())
}()
w, errAndWarnings := Load(ctx, workspacePath)
if errAndWarnings.GetError() == nil {
w, errAndWarnings := LoadWorkspaceVars(ctx)
if errAndWarnings.GetError() != nil {
return w, errAndWarnings
}
var missingVariablesError steampipeconfig.MissingVariableError
ok := errors.As(errAndWarnings.GetError(), &missingVariablesError)
// if there was an error which is NOT a MissingVariableError, return it
if !ok {
return nil, errAndWarnings
}
// if there are missing transitive dependency variables, fail as we do not prompt for these
if len(missingVariablesError.MissingTransitiveVariables) > 0 {
return nil, errAndWarnings
}
// if interactive input is disabled, return the missing variables error
if !viper.GetBool(constants.ArgInput) {
return nil, error_helpers.NewErrorsAndWarning(missingVariablesError)
}
// so we have missing variables - prompt for them
// first hide spinner if it is there
statushooks.Done(ctx)
if err := promptForMissingVariables(ctx, missingVariablesError.MissingVariables, workspacePath); err != nil {
log.Printf("[TRACE] Interactive variables prompting returned error %v", err)
return nil, error_helpers.NewErrorsAndWarning(err)
}
// ok we should have all variables now - reload workspace
return Load(ctx, workspacePath)
// load the workspace mod
errAndWarnings = w.LoadWorkspaceMod(ctx)
return w, errAndWarnings
}
func promptForMissingVariables(ctx context.Context, missingVariables []*modconfig.Variable, workspacePath string) error {

View File

@@ -3,6 +3,7 @@ package workspace
import (
"bufio"
"context"
"errors"
"fmt"
"log"
"os"
@@ -24,6 +25,7 @@ import (
"github.com/turbot/steampipe/pkg/error_helpers"
"github.com/turbot/steampipe/pkg/filepaths"
"github.com/turbot/steampipe/pkg/modinstaller"
"github.com/turbot/steampipe/pkg/statushooks"
"github.com/turbot/steampipe/pkg/steampipeconfig"
"github.com/turbot/steampipe/pkg/steampipeconfig/modconfig"
"github.com/turbot/steampipe/pkg/steampipeconfig/parse"
@@ -62,10 +64,13 @@ type Workspace struct {
loadPseudoResources bool
// channel used to send dashboard events to the handleDashboardEvent goroutine
dashboardEventChan chan dashboardevents.DashboardEvent
allVariables *modconfig.ModVariableMap
}
// Load creates a Workspace and loads the workspace mod
func Load(ctx context.Context, workspacePath string) (*Workspace, *error_helpers.ErrorAndWarnings) {
// LoadWorkspaceVars creates a Workspace and loads the variables
func LoadWorkspaceVars(ctx context.Context) (*Workspace, *error_helpers.ErrorAndWarnings) {
workspacePath := viper.GetString(constants.ArgModLocation)
utils.LogTime("workspace.Load start")
defer utils.LogTime("workspace.Load end")
@@ -74,9 +79,15 @@ func Load(ctx context.Context, workspacePath string) (*Workspace, *error_helpers
return nil, error_helpers.NewErrorsAndWarning(err)
}
// load the workspace mod
errAndWarnings := workspace.loadWorkspaceMod(ctx)
return workspace, errAndWarnings
// check if your workspace path is home dir and if modfile exists - if yes then warn and ask user to continue or not
if err := HomeDirectoryModfileCheck(ctx, workspacePath); err != nil {
return nil, error_helpers.NewErrorsAndWarning(err)
}
errorsAndWarnings := workspace.populateVariables(ctx)
if errorsAndWarnings.Error != nil {
return nil, errorsAndWarnings
}
return workspace, errorsAndWarnings
}
// LoadVariables creates a Workspace and uses it to load all variables, ignoring any value resolution errors
@@ -224,29 +235,28 @@ func (w *Workspace) setModfileExists() {
}
}
// TODO comment
// FindModFilePath looks in the current folder for mod.sp or mod.pp
// if not found it looks in the parent folder - right up to the root
func FindModFilePath(folder string) (string, error) {
folder, err := filepath.Abs(folder)
if err != nil {
return "", err
}
modFilePath := filepaths.ModFilePath(folder)
_, err = os.Stat(modFilePath)
if err == nil {
// found the modfile
return modFilePath, nil
for _, modFilePath := range filepaths.ModFilePaths(folder) {
_, err = os.Stat(modFilePath)
if err == nil {
// found the modfile
return modFilePath, nil
}
}
if os.IsNotExist(err) {
// if the file wasn't found, search in the parent directory
parent := filepath.Dir(folder)
if folder == parent {
// this typically means that we are already in the root directory
return "", ErrorNoModDefinition
}
return FindModFilePath(filepath.Dir(folder))
// if the file wasn't found, search in the parent directory
parent := filepath.Dir(folder)
if folder == parent {
// this typically means that we are already in the root directory
return "", ErrorNoModDefinition
}
return modFilePath, nil
return FindModFilePath(filepath.Dir(folder))
}
func HomeDirectoryModfileCheck(ctx context.Context, workspacePath string) error {
@@ -258,8 +268,13 @@ func HomeDirectoryModfileCheck(ctx context.Context, workspacePath string) error
// get the cmd and home dir
cmd := viper.Get(constants.ConfigKeyActiveCommand).(*cobra.Command)
home, _ := os.UserHomeDir()
_, err := os.Stat(filepaths.ModFilePath(workspacePath))
modFileExists := !os.IsNotExist(err)
var modFileExists bool
for _, modFilePath := range filepaths.ModFilePaths(workspacePath) {
if _, err := os.Stat(modFilePath); err == nil {
modFileExists = true
}
}
// check if your workspace path is home dir and if modfile exists
if workspacePath == home && modFileExists {
@@ -289,24 +304,8 @@ func HomeDirectoryModfileCheck(ctx context.Context, workspacePath string) error
return nil
}
func (w *Workspace) loadWorkspaceMod(ctx context.Context) *error_helpers.ErrorAndWarnings {
// check if your workspace path is home dir and if modfile exists - if yes then warn and ask user to continue or not
if err := HomeDirectoryModfileCheck(ctx, w.Path); err != nil {
return error_helpers.NewErrorsAndWarning(err)
}
// resolve values of all input variables
// we WILL validate missing variables when loading
validateMissing := true
inputVariables, errorsAndWarnings := w.getInputVariables(ctx, validateMissing)
if errorsAndWarnings.Error != nil {
return errorsAndWarnings
}
// populate the parsed variable values
w.VariableValues, errorsAndWarnings.Error = inputVariables.GetPublicVariableValues()
if errorsAndWarnings.Error != nil {
return errorsAndWarnings
}
func (w *Workspace) LoadWorkspaceMod(ctx context.Context) *error_helpers.ErrorAndWarnings {
var errorsAndWarnings = &error_helpers.ErrorAndWarnings{}
// build run context which we use to load the workspace
parseCtx, err := w.getParseContext(ctx)
@@ -315,8 +314,6 @@ func (w *Workspace) loadWorkspaceMod(ctx context.Context) *error_helpers.ErrorAn
return errorsAndWarnings
}
// add evaluated variables to the context
parseCtx.AddInputVariableValues(inputVariables)
// do not reload variables as we already have them
parseCtx.BlockTypeExclusions = []string{modconfig.BlockTypeVariable}
@@ -343,6 +340,54 @@ func (w *Workspace) loadWorkspaceMod(ctx context.Context) *error_helpers.ErrorAn
return errorsAndWarnings
}
func (w *Workspace) populateVariables(ctx context.Context) *error_helpers.ErrorAndWarnings {
// resolve values of all input variables
// we WILL validate missing variables when loading
validateMissing := true
inputVariables, errorsAndWarnings := w.getInputVariables(ctx, validateMissing)
if errorsAndWarnings.Error != nil {
// so there was an error - was it missing variables error
var missingVariablesError steampipeconfig.MissingVariableError
ok := errors.As(errorsAndWarnings.GetError(), &missingVariablesError)
// if there was an error which is NOT a MissingVariableError, return it
if !ok {
return errorsAndWarnings
}
// if there are missing transitive dependency variables, fail as we do not prompt for these
if len(missingVariablesError.MissingTransitiveVariables) > 0 {
return errorsAndWarnings
}
// if interactive input is disabled, return the missing variables error
if !viper.GetBool(constants.ArgInput) {
return error_helpers.NewErrorsAndWarning(missingVariablesError)
}
// so we have missing variables - prompt for them
// first hide spinner if it is there
statushooks.Done(ctx)
if err := promptForMissingVariables(ctx, missingVariablesError.MissingVariables, w.Path); err != nil {
log.Printf("[TRACE] Interactive variables prompting returned error %v", err)
return error_helpers.NewErrorsAndWarning(err)
}
// now try to load vars again
inputVariables, errorsAndWarnings = w.getInputVariables(ctx, validateMissing)
if errorsAndWarnings.Error != nil {
return errorsAndWarnings
}
}
// store the full variable map
w.allVariables = inputVariables
// populate the parsed variable values
w.VariableValues, errorsAndWarnings.Error = inputVariables.GetPublicVariableValues()
if errorsAndWarnings.Error == nil {
return errorsAndWarnings
}
return errorsAndWarnings
}
func (w *Workspace) getInputVariables(ctx context.Context, validateMissing bool) (*modconfig.ModVariableMap, *error_helpers.ErrorAndWarnings) {
// build a run context just to use to load variable definitions
variablesParseCtx, err := w.getParseContext(ctx)
@@ -386,6 +431,11 @@ func (w *Workspace) getParseContext(ctx context.Context) (*parse.ModParseContext
Include: filehelpers.InclusionsFromExtensions(constants.ModDataExtensions),
})
// add any evaluated variables to the context
if w.allVariables != nil {
parseCtx.AddInputVariableValues(w.allVariables)
}
return parseCtx, nil
}

View File

@@ -128,7 +128,7 @@ func (w *Workspace) reloadResourceMaps(ctx context.Context) (*modconfig.Resource
}
// now reload the workspace
errAndWarnings := w.loadWorkspaceMod(ctx)
errAndWarnings := w.LoadWorkspaceMod(ctx)
if errAndWarnings.GetError() != nil {
// check the existing watcher error - if we are already in an error state, do not show error
if w.watcherError == nil {

View File

@@ -1,33 +0,0 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically wh.en used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# vendor/
# Ignore JetBrains files
.idea
# Ignore swap files
*.swo
*.swp
# Parliament IAM permissions outputs
scripts/generate_parliament_iam_permissions/__pycache__
scripts/generate_parliament_iam_permissions/docs
scripts/generate_parliament_iam_permissions/generate_go_file.
# Ignore node dependencies
node_modules
# Ignore file types
.vscode/launch.json

View File

@@ -1,17 +0,0 @@
variable dep_mod_var1 {
type = string
}
variable dep_mod_var2 {
type = string
}
variable dupe_name_var {
type = string
}
query "m1_q1"{
sql = "select 1 as query"
}

View File

@@ -6,3 +6,5 @@ m1.dep_mod_var1 = "select 'm1.dep_mod_var_set_in_file' as a"
m1.dupe_name_var = "select 'm1.dupe_name_var_set_in_file' as a"
dupe_name_var = "select 'dupe_name_var_set_in_file' as a"
m1.dep_mod_var2 = "bar"

View File

@@ -0,0 +1,28 @@
benchmark "all_controls_ok" {
title = "All controls in OK, no ALARMS/ERORS"
description = "Benchmark to verify the exit code when no controls are in error/alarm"
children = [
control.ok_1,
control.ok_2
]
}
control "ok_1" {
title = "Control to verify the exit code when no controls are in error/alarm"
description = "Control to verify the exit code when no controls are in error/alarm"
query = query.query_1
severity = "high"
}
control "ok_2" {
title = "Control to verify the exit code when no controls are in error/alarm"
description = "Control to verify the exit code when no controls are in error/alarm"
query = query.query_1
severity = "high"
}
query "query_1"{
title ="query_1"
description = "Simple query 1"
sql = "select 'ok' as status, 'steampipe' as resource, 'acceptance tests' as reason"
}

View File

@@ -0,0 +1,21 @@
benchmark "check_cache_benchmark" {
title = "Benchmark to test the cache functionality in steampipe"
children = [
control.cache_test_1,
control.cache_test_2
]
}
control "cache_test_1" {
title = "Control to test cache functionality 1"
description = "Control to test cache functionality in steampipe."
sql = query.check_cache.sql
severity = "high"
}
control "cache_test_2" {
title = "Control to test cache functionality 2"
description = "Control to test cache functionality in steampipe."
sql = query.check_cache.sql
severity = "high"
}

View File

@@ -0,0 +1,191 @@
benchmark "query_and_control_parameters_benchmark" {
title = "Benchmark to test the query and control parameter functionalities in steampipe"
children = [
control.query_params_with_defaults_and_no_args,
control.query_params_with_defaults_and_partial_named_args,
control.query_params_with_defaults_and_partial_positional_args,
control.query_params_with_defaults_and_all_named_args,
control.query_params_with_defaults_and_all_positional_args,
control.query_params_with_no_defaults_and_no_args,
control.query_params_with_no_defaults_with_named_args,
control.query_params_with_no_defaults_with_positional_args,
control.query_params_array_with_default,
control.query_params_map_with_default,
control.query_params_invalid_arg_syntax,
control.query_inline_sql_from_control_with_partial_named_args,
control.query_inline_sql_from_control_with_partial_positional_args,
control.query_inline_sql_from_control_with_no_args,
control.query_inline_sql_from_control_with_all_positional_args,
control.query_inline_sql_from_control_with_all_named_args
]
}
control "query_params_with_defaults_and_no_args" {
title = "Control to test query param functionality with defaults(and no args passed)"
query = query.query_params_with_all_defaults
}
control "query_params_with_defaults_and_partial_named_args" {
title = "Control to test query param functionality with defaults(and some named args passed in query)"
query = query.query_params_with_all_defaults
args = {
"p2" = "command_parameter_2"
}
}
control "query_params_with_defaults_and_partial_positional_args" {
title = "Control to test query param functionality with defaults(and some positional args passed in query)"
query = query.query_params_with_all_defaults
args = [ "command_parameter_1" ]
}
control "query_params_with_defaults_and_all_named_args" {
title = "Control to test query param functionality with defaults(and all named args passed in query)"
query = query.query_params_with_all_defaults
args = {
"p1" = "command_parameter_1"
"p2" = "command_parameter_2"
"p3" = "command_parameter_3"
}
}
control "query_params_with_defaults_and_all_positional_args" {
title = "Control to test query param functionality with defaults(and all positional args passed in query)"
query = query.query_params_with_all_defaults
args = [ "command_parameter_1", "command_parameter_2", "command_parameter_3" ]
}
control "query_params_with_no_defaults_and_no_args" {
title = "Control to test query param functionality with no defaults(and no args passed)"
query = query.query_params_with_no_defaults
}
control "query_params_with_no_defaults_with_named_args" {
title = "Control to test query param functionality with no defaults(and args passed in query)"
query = query.query_params_with_no_defaults
args = {
"p1" = "command_parameter_1"
"p2" = "command_parameter_2"
"p3" = "command_parameter_3"
}
}
control "query_params_with_no_defaults_with_positional_args" {
title = "Control to test query param functionality with no defaults(and positional args passed in query)"
query = query.query_params_with_no_defaults
args = [ "command_parameter_1", "command_parameter_2","command_parameter_3" ]
}
control "query_params_array_with_default" {
title = "Control to test query param functionality with an array param with default(and no args passed)"
query = query.query_array_params_with_default
}
control "query_params_map_with_default" {
title = "Control to test query param functionality with a map param with default(and no args passed)"
query = query.query_map_params_with_default
}
control "query_params_invalid_arg_syntax" {
title = "Control to test query param functionality with a map param with no default(and invalid args passed in query)"
query = query.query_map_params_with_no_default
args = {
"p1" = "command_parameter_1"
}
}
control "query_inline_sql_from_control_with_partial_named_args" {
title = "Control to test the inline sql functionality within a control with defaults(and some named args passed in control)"
sql = "select 'ok' as status, 'steampipe' as resource, concat($1::text, ' ', $2::text, ' ', $3::text) as reason"
param "p1"{
description = "p1"
default = "default_parameter_1"
}
param "p2"{
description = "p2"
default = "default_parameter_2"
}
param "p3"{
description = "p3"
default = "default_parameter_3"
}
args = {
"p1" = "command_parameter_1"
"p3" = "command_parameter_3"
}
}
control "query_inline_sql_from_control_with_partial_positional_args" {
title = "Control to test the inline sql functionality within a control with defaults(and some positional args passed in control)"
sql = "select 'ok' as status, 'steampipe' as resource, concat($1::text, ' ', $2::text, ' ', $3::text) as reason"
param "p1"{
description = "p1"
default = "default_parameter_1"
}
param "p2"{
description = "p2"
default = "default_parameter_2"
}
param "p3"{
description = "p3"
default = "default_parameter_3"
}
args = [ "command_parameter_1", "command_parameter_2" ]
}
control "query_inline_sql_from_control_with_no_args" {
title = "Control to test the inline sql functionality within a control with defaults(and no args passed in control)"
sql = "select 'ok' as status, 'steampipe' as resource, concat($1::text, ' ', $2::text, ' ', $3::text) as reason"
param "p1"{
description = "p1"
default = "default_parameter_1"
}
param "p2"{
description = "p2"
default = "default_parameter_2"
}
param "p3"{
description = "p3"
default = "default_parameter_3"
}
}
control "query_inline_sql_from_control_with_all_positional_args" {
title = "Control to test the inline sql functionality within a control with defaults(and all positional args passed in control)"
sql = "select 'ok' as status, 'steampipe' as resource, concat($1::text, ' ', $2::text, ' ', $3::text) as reason"
param "p1"{
description = "p1"
default = "default_parameter_1"
}
param "p2"{
description = "p2"
default = "default_parameter_2"
}
param "p3"{
description = "p3"
default = "default_parameter_3"
}
args = [ "command_parameter_1", "command_parameter_2", "command_parameter_3" ]
}
control "query_inline_sql_from_control_with_all_named_args" {
title = "Control to test the inline sql functionality within a control with defaults(and all named args passed in control)"
sql = "select 'ok' as status, 'steampipe' as resource, concat($1::text, ' ', $2::text, ' ', $3::text) as reason"
param "p1"{
description = "p1"
default = "default_parameter_1"
}
param "p2"{
description = "p2"
default = "default_parameter_2"
}
param "p3"{
description = "p3"
default = "default_parameter_3"
}
args = {
"p1" = "command_parameter_1"
"p2" = "command_parameter_2"
"p3" = "command_parameter_3"
}
}

View File

@@ -0,0 +1,45 @@
benchmark "control_summary_benchmark" {
title = "Benchmark to test the check summary output in steampipe"
children = [
control.sample_control_1,
control.sample_control_2,
control.sample_control_3,
control.sample_control_4,
control.sample_control_5
]
}
control "sample_control_1" {
title = "Sample control 1"
description = "A sample control"
sql = query.static_query.sql
severity = "high"
}
control "sample_control_2" {
title = "Sample control 2"
description = "A sample control"
sql = query.static_query.sql
severity = "critical"
}
control "sample_control_3" {
title = "Sample control 3"
description = "A sample control"
sql = query.static_query.sql
severity = "high"
}
control "sample_control_4" {
title = "Sample control 4"
description = "A sample control that returns ERROR"
sql = query.static_query.sql
severity = "critical"
}
control "sample_control_5" {
title = "Sample control 5"
description = "A sample control"
sql = query.static_query.sql
severity = "high"
}

View File

@@ -0,0 +1,29 @@
benchmark "check_plugin_crash_benchmark" {
title = "Benchmark to test the plugin crash bug while running controls"
children = [
control.plugin_chaos_test_1,
control.plugin_crash_test,
control.plugin_chaos_test_2
]
}
control "plugin_chaos_test_1" {
title = "Control to query a chaos table"
description = "Control to query a chaos table to test all flavours of integer and float data types"
sql = query.check_plugincrash_normalquery1.sql
severity = "high"
}
control "plugin_crash_test" {
title = "Control to simulate a plugin crash"
description = "Control to query a chaos table that prints 50 rows and do an os.Exit(-1) to simulate a plugin crash"
sql = "select * from chaos_plugin_crash"
severity = "high"
}
control "plugin_chaos_test_2" {
title = "Control to query a chaos table"
description = "Control to query a chaos table test the Get call with all the possible scenarios like errors, panics and delays"
sql = query.check_plugincrash_normalquery2.sql
severity = "high"
}

View File

@@ -0,0 +1,4 @@
mod "functionality_test_mod_pp"{
title = "Functionality test mod with pp files"
description = "This is a simple mod used for testing different steampipe features and funtionalities."
}

View File

@@ -0,0 +1,8 @@
select
case
when mod(id,2)=0 then 'alarm'
when mod(id,2)=1 then 'ok'
end status,
unique_col as resource,
id as reason
from chaos.chaos_cache_check where id=2

View File

@@ -0,0 +1,8 @@
select
case
when mod(id,2)=0 then 'alarm'
when mod(id,2)=1 then 'ok'
end status,
int8_data as resource,
int16_data as reason
from chaos_all_numeric_column

View File

@@ -0,0 +1,8 @@
select
case
when mod(id,2)=0 then 'alarm'
when mod(id,2)=1 then 'ok'
end status,
fatal_error as resource,
retryable_error as reason
from chaos_get_errors limit 10

View File

@@ -0,0 +1,56 @@
query "query_params_with_all_defaults"{
description = "query 1 - 3 params all with defaults"
sql = "select 'ok' as status, 'steampipe' as resource, concat($1::text, ' ', $2::text, ' ', $3::text) as reason"
param "p1"{
description = "First parameter"
default = "default_parameter_1"
}
param "p2"{
description = "Second parameter"
default = "default_parameter_2"
}
param "p3"{
description = "Third parameter"
default = "default_parameter_3"
}
}
query "query_params_with_no_defaults"{
description = "query 1 - 3 params with no defaults"
sql = "select 'ok' as status, 'steampipe' as resource, concat($1::text, ' ', $2::text, ' ', $3::text) as reason"
param "p1"{
description = "First parameter"
}
param "p2"{
description = "Second parameter"
}
param "p3"{
description = "Third parameter"
}
}
query "query_array_params_with_default"{
description = "query an array parameter with default"
sql = "select 'ok' as status, 'steampipe' as resource, $1::jsonb->1 as reason"
param "p1"{
description = "Array parameter"
default = ["default_p1_element_01", "default_p1_element_02", "default_p1_element_03"]
}
}
query "query_map_params_with_default"{
description = "query a map parameter with default"
sql = "select 'ok' as status, 'steampipe' as resource, $1::json->'default_property_01' as reason"
param "p1"{
description = "Map parameter"
default = {"default_property_01": "default_property_value_01", "default_property_02": "default_property_value_02"}
}
}
query "query_map_params_with_no_default"{
description = "query a map parameter with no default"
sql = "select 'ok' as status, 'steampipe' as resource, $1::json->'default_property_01' as reason"
param "p1"{
description = "Map parameter"
}
}

View File

@@ -0,0 +1,11 @@
WITH s_path AS (select setting from pg_settings where name='search_path')
SELECT s_path.setting as resource,
CASE
WHEN s_path.setting LIKE 'aws%' THEN 'ok'
ELSE 'alarm'
END as status,
CASE
WHEN s_path.setting LIKE 'aws%' THEN 'Starts with "aws"'
ELSE 'Does not start with "aws"'
END as reason
FROM s_path

View File

@@ -0,0 +1,11 @@
WITH s_path AS (select setting from pg_settings where name='search_path')
SELECT s_path.setting as resource,
CASE
WHEN s_path.setting LIKE 'chaos, b, c%' THEN 'ok'
ELSE 'alarm'
END as status,
CASE
WHEN s_path.setting LIKE 'aws%' THEN 'Starts with "chaos, b, c"'
ELSE 'Does not start with "chaos, b, c"'
END as reason
FROM s_path

View File

@@ -0,0 +1,19 @@
select
case
when num=1 then 'ok'
when mod(num,2)=0 then 'alarm'
when mod(num,3)=0 then 'ok'
when mod(num,5)=0 then 'error'
when mod(num,7)=0 then 'info'
when mod(num,11)=0 then 'skip'
end status,
'steampipe' as resource,
case
when num=1 then 'ok'
when mod(num,2)=0 then 'alarm'
when mod(num,3)=0 then 'ok'
when mod(num,5)=0 then 'error'
when mod(num,7)=0 then 'info'
when mod(num,11)=0 then 'skip'
end reason
from generate_series(1, 12) num

View File

@@ -0,0 +1,19 @@
select
case
when num=1 then 'ok'
when mod(num,2)=0 then 'alarm'
when mod(num,3)=0 then 'ok'
when mod(num,5)=0 then 'error'
when mod(num,7)=0 then 'info'
when mod(num,11)=0 then 'skip'
end status,
num as resource,
case
when num=1 then 'ok'
when mod(num,2)=0 then 'alarm'
when mod(num,3)=0 then 'ok'
when mod(num,5)=0 then 'error'
when mod(num,7)=0 then 'info'
when mod(num,11)=0 then 'skip'
end reason
from generate_series(1, 12) num

View File

@@ -0,0 +1,7 @@
mod "local_mod_with_args_in_require" {
require {
mod "github.com/pskrbasu/steampipe-mod-dependency-vars-1" {
version = "*"
}
}
}

View File

@@ -0,0 +1,12 @@
control "check_1" {
title = "Control to verify mod.sp traversal functionality"
description = "Control to verify verify mod.sp traversal functionality."
query = query.query_1
severity = "high"
}
query "query_1"{
title ="query_1"
description = "Simple query 1"
sql = "select 'ok' as status, 'steampipe' as resource, 'acceptance tests' as reason"
}

View File

@@ -0,0 +1,4 @@
mod "nested_mod"{
title = "Nested mod"
description = "This is a nested mod used for testing the mod.pp resolution traversal up the directory tree feature. This mod is needed in acceptance tests. Do not expand this mod."
}

View File

@@ -0,0 +1 @@
dependency_vars_1.version = "v8.0.0"

View File

@@ -0,0 +1,11 @@
{
"test_vars_dependency_mod": {
"github.com/pskrbasu/steampipe-mod-dependency-vars-1": {
"name": "github.com/pskrbasu/steampipe-mod-dependency-vars-1",
"alias": "dependency_vars_1",
"version": "2.0.0",
"constraint": "*",
"struct_version": 20220411
}
}
}

View File

@@ -0,0 +1,15 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# vendor/

View File

@@ -0,0 +1,2 @@
# steampipe-mod-dependency-vars-1
steampipe mod to test mod dependency edge cases

View File

@@ -0,0 +1,11 @@
query "version" {
sql = "select $1::text as reason, $1::text as resource, 'ok' as status"
param "p1"{
description = "p1"
default = var.version
}
}
variable "version"{
type = string
}

View File

@@ -0,0 +1,8 @@
mod "test_vars_dependency_mod" {
title = "test_vars_dependency_mod"
require {
mod "github.com/pskrbasu/steampipe-mod-dependency-vars-1" {
version = "*"
}
}
}

View File

@@ -0,0 +1,11 @@
{
"test_vars_dependency_mod": {
"github.com/pskrbasu/steampipe-mod-dependency-vars-1": {
"name": "github.com/pskrbasu/steampipe-mod-dependency-vars-1",
"alias": "dependency_vars_1",
"version": "2.0.0",
"constraint": "*",
"struct_version": 20220411
}
}
}

View File

@@ -0,0 +1,15 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# vendor/

View File

@@ -0,0 +1,2 @@
# steampipe-mod-dependency-vars-1
steampipe mod to test mod dependency edge cases

View File

@@ -0,0 +1,11 @@
query "version" {
sql = "select $1::text as reason, $1::text as resource, 'ok' as status"
param "p1"{
description = "p1"
default = var.version
}
}
variable "version"{
type = string
}

View File

@@ -0,0 +1,8 @@
mod "test_vars_dependency_mod" {
title = "test_vars_dependency_mod"
require {
mod "github.com/pskrbasu/steampipe-mod-dependency-vars-1" {
version = "*"
}
}
}

View File

@@ -0,0 +1 @@
dependency_vars_1.version = "v7.0.0"

View File

@@ -0,0 +1,16 @@
# test_workspace_mod_var_precedence_set_from_command_line_and_both_spvars
### Description
This mod is used to test variable resolution precedence in a mod by passing the --var command line arg, a steampipe.spvars file and an *.auto.spvars file. The mod also has a default value of variable 'version' set.
### Usage
This mod is used in the tests in `mod_vars.bats` to simulate a scenario where the version defined in the mod is picked from the --var command line argument over the steampipe.spvars and *.auto.spvars file and over the default value of variable 'version' set in the mod, because command line arguments have higher precendence.
Steampipe loads variables in the following order, with later sources taking precedence over earlier ones:
1. Environment variables
2. The steampipe.spvars file, if present.
3. Any *.auto.spvars files, in alphabetical order by filename.
4. Any --var and --var-file options on the command line, in the order they are provided.

View File

@@ -0,0 +1,16 @@
mod "test_vars_workspace_mod" {
title = "test_vars_workspace_mod"
}
query "version" {
sql = "select $1::text as reason, $1::text as resource, 'ok' as status"
param "p1"{
description = "p1"
default = var.version
}
}
variable "version"{
type = string
default = "v2.0.0"
}

View File

@@ -0,0 +1,10 @@
# test_workspace_mod_var_set_from_auto_spvars
### Description
This mod is used to test variable resolution in a mod by passing the variable value in an auto spvars file. The mod has a default value of variable 'version' set.
### Usage
This mod is used in the tests in `mod_vars.bats` to simulate a scenario where the version defined in the mod is picked from the passed
variable value in an suto spvars file over the default value of variable 'version' set in the mod.

View File

@@ -0,0 +1,16 @@
mod "test_vars_workspace_mod" {
title = "test_vars_workspace_mod"
}
query "version" {
sql = "select $1::text as reason, $1::text as resource, 'ok' as status"
param "p1"{
description = "p1"
default = var.version
}
}
variable "version"{
type = string
default = "v2.0.0"
}

View File

@@ -0,0 +1,10 @@
# test_workspace_mod_var_set_from_explicit_spvars
### Description
This mod is used to test variable resolution in a mod by passing the variable value in an explicit spvars file. The mod has a default value of variable 'version' set.
### Usage
This mod is used in the tests in `mod_vars.bats` to simulate a scenario where the version defined in the mod is picked from the passed
variable value in an explicit spvars file over the default value of variable 'version' set in the mod.

View File

@@ -0,0 +1,16 @@
mod "test_vars_workspace_mod" {
title = "test_vars_workspace_mod"
}
query "version" {
sql = "select $1::text as reason, $1::text as resource, 'ok' as status"
param "p1"{
description = "p1"
default = var.version
}
}
variable "version"{
type = string
default = "v2.0.0"
}

View File

@@ -0,0 +1,10 @@
# test_workspace_mod_var_set_from_auto_spvars
### Description
This mod is used to test variable resolution in a mod by passing the variable value in an auto spvars file. The mod has a default value of variable 'version' set.
### Usage
This mod is used in the tests in `mod_vars.bats` to simulate a scenario where the version defined in the mod is picked from the passed
variable value in an suto spvars file over the default value of variable 'version' set in the mod.

View File

@@ -0,0 +1,16 @@
mod "test_vars_workspace_mod" {
title = "test_vars_workspace_mod"
}
query "version" {
sql = "select $1::text as reason, $1::text as resource, 'ok' as status"
param "p1"{
description = "p1"
default = var.version
}
}
variable "version"{
type = string
default = "v2.0.0"
}

View File

@@ -0,0 +1,10 @@
# test_workspace_mod_var_set_from_auto_spvars
### Description
This mod is used to test variable resolution in a mod by passing the variable value in an auto spvars file. The mod has a default value of variable 'version' set.
### Usage
This mod is used in the tests in `mod_vars.bats` to simulate a scenario where the version defined in the mod is picked from the passed
variable value in an suto spvars file over the default value of variable 'version' set in the mod.

View File

@@ -0,0 +1,16 @@
mod "test_vars_workspace_mod" {
title = "test_vars_workspace_mod"
}
query "version" {
sql = "select $1::text as reason, $1::text as resource, 'ok' as status"
param "p1"{
description = "p1"
default = var.version
}
}
variable "version"{
type = string
default = "v2.0.0"
}

View File

@@ -21,8 +21,23 @@ load "$LIB_BATS_SUPPORT/load.bash"
v5.0.0,v5.0.0,ok'
}
@test "test variable resolution in workspace mod set from auto spvars file" {
cd $FILE_PATH/test_data/mods/test_workspace_mod_var_set_from_auto_spvars
@test "test variable resolution in workspace mod set from steampipe.spvars file" {
cd $FILE_PATH/test_data/mods/test_workspace_mod_var_set_from_steampipe.spvars
run steampipe query query.version --output csv
# check the output - query should use the value of variable set from the steampipe spvars
# file ("v7.0.0") which will give the output:
# +--------+----------+--------+
# | reason | resource | status |
# +--------+----------+--------+
# | v7.0.0 | v7.0.0 | ok |
# +--------+----------+--------+
assert_output 'reason,resource,status
v7.0.0,v7.0.0,ok'
}
@test "test variable resolution in workspace mod set from *.auto.spvars file" {
cd $FILE_PATH/test_data/mods/test_workspace_mod_var_set_from_auto.spvars
run steampipe query query.version --output csv
# check the output - query should use the value of variable set from the auto spvars
@@ -88,7 +103,7 @@ v5.0.0,v5.0.0,ok'
}
@test "test variable resolution in dependency mod set from steampipe.spvars file" {
cd $FILE_PATH/test_data/mods/test_dependency_mod_var_set_from_auto_spvars
cd $FILE_PATH/test_data/mods/test_dependency_mod_var_set_from_steampipe.spvars
run steampipe query dependency_vars_1.query.version --output csv
# check the output - query should use the value of variable set from the steampipe.spvars
@@ -103,7 +118,7 @@ v7.0.0,v7.0.0,ok'
}
@test "test variable resolution in dependency mod set from *.auto.spvars spvars file" {
cd $FILE_PATH/test_data/mods/test_dependency_mod_var_set_from_explicit_spvars
cd $FILE_PATH/test_data/mods/test_dependency_mod_var_set_from_auto.spvars
run steampipe query dependency_vars_1.query.version --output csv
# check the output - query should use the value of variable set from the *.auto.spvars
@@ -135,7 +150,7 @@ v8.0.0,v8.0.0,ok'
}
@test "test variable resolution precedence in workspace mod set from steampipe.spvars and ENV" {
cd $FILE_PATH/test_data/mods/test_workspace_mod_var_set_from_auto_spvars
cd $FILE_PATH/test_data/mods/test_workspace_mod_var_set_from_steampipe.spvars
export SP_VAR_version=v9.0.0
run steampipe query query.version --output csv
# check the output - query should use the value of variable set from the steampipe.spvars("v7.0.0") file over

Some files were not shown because too many files have changed in this diff Show More