2018-05-21 16:26:22 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"path/filepath"
|
2018-06-18 17:08:23 +00:00
|
|
|
"regexp"
|
2018-05-21 16:26:22 +00:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/ghodss/yaml"
|
|
|
|
"github.com/kolide/fleet/server/kolide"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/urfave/cli"
|
|
|
|
)
|
|
|
|
|
|
|
|
func specGroupFromPack(name string, inputPack kolide.PermissivePackContent) (*specGroup, error) {
|
|
|
|
specs := &specGroup{
|
|
|
|
Queries: []*kolide.QuerySpec{},
|
|
|
|
Packs: []*kolide.PackSpec{},
|
|
|
|
Labels: []*kolide.LabelSpec{},
|
|
|
|
}
|
|
|
|
|
|
|
|
pack := &kolide.PackSpec{
|
|
|
|
Name: name,
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, query := range inputPack.Queries {
|
|
|
|
spec := &kolide.QuerySpec{
|
|
|
|
Name: name,
|
|
|
|
Description: query.Description,
|
|
|
|
Query: query.Query,
|
|
|
|
}
|
|
|
|
|
|
|
|
interval := uint(0)
|
|
|
|
switch i := query.Interval.(type) {
|
|
|
|
case string:
|
|
|
|
u64, err := strconv.ParseUint(i, 10, 32)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrap(err, "converting interval from string to uint")
|
|
|
|
}
|
|
|
|
interval = uint(u64)
|
|
|
|
case uint:
|
|
|
|
interval = i
|
2018-12-21 01:43:00 +00:00
|
|
|
case float64:
|
|
|
|
interval = uint(i)
|
2018-05-21 16:26:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
specs.Queries = append(specs.Queries, spec)
|
|
|
|
pack.Queries = append(pack.Queries, kolide.PackSpecQuery{
|
|
|
|
Name: name,
|
|
|
|
QueryName: name,
|
|
|
|
Interval: interval,
|
|
|
|
Description: query.Description,
|
|
|
|
Snapshot: query.Snapshot,
|
|
|
|
Removed: query.Removed,
|
|
|
|
Shard: query.Shard,
|
|
|
|
Platform: query.Platform,
|
|
|
|
Version: query.Version,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
specs.Packs = append(specs.Packs, pack)
|
|
|
|
|
|
|
|
return specs, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func convertCommand() cli.Command {
|
|
|
|
var (
|
|
|
|
flFilename string
|
|
|
|
flDebug bool
|
|
|
|
)
|
|
|
|
return cli.Command{
|
|
|
|
Name: "convert",
|
|
|
|
Usage: "Convert osquery packs into decomposed fleet configs",
|
|
|
|
UsageText: `fleetctl convert [options]`,
|
|
|
|
Flags: []cli.Flag{
|
|
|
|
configFlag(),
|
|
|
|
contextFlag(),
|
|
|
|
cli.StringFlag{
|
|
|
|
Name: "f",
|
|
|
|
EnvVar: "FILENAME",
|
|
|
|
Value: "",
|
|
|
|
Destination: &flFilename,
|
|
|
|
Usage: "A file to apply",
|
|
|
|
},
|
|
|
|
cli.BoolFlag{
|
|
|
|
Name: "debug",
|
|
|
|
EnvVar: "DEBUG",
|
|
|
|
Destination: &flDebug,
|
|
|
|
Usage: "Whether or not to enable debug logging",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Action: func(c *cli.Context) error {
|
|
|
|
if flFilename == "" {
|
|
|
|
return errors.New("-f must be specified")
|
|
|
|
}
|
|
|
|
|
|
|
|
b, err := ioutil.ReadFile(flFilename)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-06-18 17:08:23 +00:00
|
|
|
// Remove any literal newlines (because they are not
|
|
|
|
// valid JSON but osquery accepts them) and replace
|
|
|
|
// with \n so that we get them in the YAML output where
|
|
|
|
// they are allowed.
|
2018-06-28 19:02:46 +00:00
|
|
|
re := regexp.MustCompile(`\s*\\\n`)
|
2018-06-18 17:08:23 +00:00
|
|
|
b = re.ReplaceAll(b, []byte(`\n`))
|
|
|
|
|
2018-05-21 16:26:22 +00:00
|
|
|
var specs *specGroup
|
|
|
|
|
|
|
|
var pack kolide.PermissivePackContent
|
2018-06-18 17:08:23 +00:00
|
|
|
if err := json.Unmarshal(b, &pack); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
base := filepath.Base(flFilename)
|
|
|
|
specs, err = specGroupFromPack(strings.TrimSuffix(base, filepath.Ext(base)), pack)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2018-05-22 18:48:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if specs == nil {
|
|
|
|
return errors.New("could not parse files")
|
2018-05-21 16:26:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, pack := range specs.Packs {
|
|
|
|
spec, err := json.Marshal(pack)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
meta := specMetadata{
|
|
|
|
Kind: "pack",
|
|
|
|
Version: "v1",
|
|
|
|
Spec: spec,
|
|
|
|
}
|
|
|
|
|
|
|
|
out, err := yaml.Marshal(meta)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Println("---")
|
|
|
|
fmt.Print(string(out))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, query := range specs.Queries {
|
|
|
|
spec, err := json.Marshal(query)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
meta := specMetadata{
|
|
|
|
Kind: "query",
|
|
|
|
Version: "v1",
|
|
|
|
Spec: spec,
|
|
|
|
}
|
|
|
|
|
|
|
|
out, err := yaml.Marshal(meta)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Println("---")
|
|
|
|
fmt.Print(string(out))
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|