Documentation
¶
Overview ¶
Dynamic Tables
If plugin.SchemaMode is set to dynamic, then each time Steampipe loads a plugin it checks for schema changes since the last load. If it detects changes, Steampipe reloads the plugin.
Dynamic tables are useful when you are building a plugin whose schema is not known at compile time; instead it must be generated at runtime. The CSV plugin, for example, can load CSV files from one or more directories. Each file may have a different set of columns.
In order to create a dynamic table, plugin.TableMapFunc should call a function that returns map[string]*plugin.Table.
func Plugin(ctx context.Context) *plugin.Plugin {
p := &plugin.Plugin{
Name: "steampipe-plugin-csv",
ConnectionConfigSchema: &plugin.ConnectionConfigSchema{
NewInstance: ConfigInstance,
Schema: ConfigSchema,
},
DefaultTransform: transform.FromGo().NullIfZero(),
SchemaMode: plugin.SchemaModeDynamic,
TableMapFunc: PluginTables,
}
return p
}
func PluginTables(ctx context.Context, p *plugin.Plugin) (map[string]*plugin.Table, error) {
// Initialize tables
tables := map[string]*plugin.Table{}
// Search for CSV files to create as tables
paths, err := csvList(ctx, p)
if err != nil {
return nil, err
}
for _, i := range paths {
tableCtx := context.WithValue(ctx, "path", i)
base := filepath.Base(i)
// tableCSV returns a *plugin.Table type
tables[base[0:len(base)-len(filepath.Ext(base))]] = tableCSV(tableCtx, p)
}
return tables, nil
}
The tableCSV function mentioned above looks for all CSV files in the configured paths, and for each one, builds a *plugin.Table:
func tableCSV(ctx context.Context, p *plugin.Plugin) *plugin.Table {
path := ctx.Value("path").(string)
csvFile, err := os.Open(path)
if err != nil {
plugin.Logger(ctx).Error("Could not open CSV file", "path", path)
panic(err)
}
r := csv.NewReader(csvFile)
csvConfig := GetConfig(p.Connection)
if csvConfig.Separator != nil && *csvConfig.Separator != "" {
r.Comma = rune((*csvConfig.Separator)[0])
}
if csvConfig.Comment != nil {
if *csvConfig.Comment == "" {
// Disable comments
r.Comment = 0
} else {
// Set the comment character
r.Comment = rune((*csvConfig.Comment)[0])
}
}
// Read the header to peak at the column names
header, err := r.Read()
if err != nil {
plugin.Logger(ctx).Error("Error parsing CSV header:", "path", path, "header", header, "err", err)
panic(err)
}
cols := []*plugin.Column{}
for idx, i := range header {
cols = append(cols, &plugin.Column{
Name: i,
Type: proto.ColumnType_STRING,
Transform: transform.FromField(i),
Description: fmt.Sprintf("Field %d.", idx)
})
}
return &plugin.Table{
Name: path,
Description: fmt.Sprintf("CSV file at %s", path),
List: &plugin.ListConfig{
Hydrate: listCSVWithPath(path),
},
Columns: cols,
}
}
The end result is that, when using the CSV plugin, whenever Steampipe starts it will check for any new, deleted, and modified CSV files in the configured `paths` and create any discovered CSVs as tables. The CSV filenames are turned directly into table names.
For more information on how the CSV plugin can be queried as a result of being a dynamic table, please see the CSV plugin.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type ForceImport ¶
type ForceImport string
ForceImport is a mechanism to ensure godoc can reference all required packages