cscli hub list: show only non-empty tables with -o human
* agent config: remove unused LintOnly bool * Item.IsLocal() -> Item.State.IsLocal(); split method InstallStatus() * cscli hub list: show only non-empty tables with -o human
This commit is contained in:
parent
486f96e7ac
commit
1ab4487b65
16 changed files with 77 additions and 77 deletions
|
@ -46,7 +46,7 @@ func backupHub(dirPath string) error {
|
|||
}
|
||||
|
||||
//for the local/tainted ones, we back up the full file
|
||||
if v.State.Tainted || v.IsLocal() || !v.State.UpToDate {
|
||||
if v.State.Tainted || v.State.IsLocal() || !v.State.UpToDate {
|
||||
//we need to backup stages for parsers
|
||||
if itemType == cwhub.PARSERS || itemType == cwhub.POSTOVERFLOWS {
|
||||
fstagedir := fmt.Sprintf("%s%s", itemDirectory, v.Stage)
|
||||
|
@ -54,7 +54,7 @@ func backupHub(dirPath string) error {
|
|||
return fmt.Errorf("error while creating stage dir %s : %s", fstagedir, err)
|
||||
}
|
||||
}
|
||||
clog.Debugf("[%s]: backing up file (tainted:%t local:%t up-to-date:%t)", k, v.State.Tainted, v.IsLocal(), v.State.UpToDate)
|
||||
clog.Debugf("[%s]: backing up file (tainted:%t local:%t up-to-date:%t)", k, v.State.Tainted, v.State.IsLocal(), v.State.UpToDate)
|
||||
tfile := fmt.Sprintf("%s%s/%s", itemDirectory, v.Stage, v.FileName)
|
||||
if err = CopyFile(v.State.LocalPath, tfile); err != nil {
|
||||
return fmt.Errorf("failed copy %s %s to %s : %s", itemType, v.State.LocalPath, tfile, err)
|
||||
|
|
|
@ -66,7 +66,7 @@ func runHubList(cmd *cobra.Command, args []string) error {
|
|||
}
|
||||
}
|
||||
|
||||
err = listItems(color.Output, cwhub.ItemTypes, items)
|
||||
err = listItems(color.Output, cwhub.ItemTypes, items, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -580,7 +580,7 @@ func itemsListRunner(it hubItemType) func(cmd *cobra.Command, args []string) err
|
|||
return err
|
||||
}
|
||||
|
||||
if err = listItems(color.Output, []string{it.name}, items); err != nil {
|
||||
if err = listItems(color.Output, []string{it.name}, items, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -53,11 +53,19 @@ func selectItems(hub *cwhub.Hub, itemType string, args []string, installedOnly b
|
|||
return items, nil
|
||||
}
|
||||
|
||||
func listItems(out io.Writer, itemTypes []string, items map[string][]*cwhub.Item) error {
|
||||
func listItems(out io.Writer, itemTypes []string, items map[string][]*cwhub.Item, omitIfEmpty bool) error {
|
||||
switch csConfig.Cscli.Output {
|
||||
case "human":
|
||||
nothingToDisplay := true
|
||||
for _, itemType := range itemTypes {
|
||||
if omitIfEmpty && len(items[itemType]) == 0 {
|
||||
continue
|
||||
}
|
||||
listHubItemTable(out, "\n"+strings.ToUpper(itemType), items[itemType])
|
||||
nothingToDisplay = false
|
||||
}
|
||||
if nothingToDisplay {
|
||||
fmt.Println("No items to display")
|
||||
}
|
||||
case "json":
|
||||
type itemHubStatus struct {
|
||||
|
@ -75,14 +83,15 @@ func listItems(out io.Writer, itemTypes []string, items map[string][]*cwhub.Item
|
|||
hubStatus[itemType] = make([]itemHubStatus, len(items[itemType]))
|
||||
|
||||
for i, item := range items[itemType] {
|
||||
status, emo := item.InstallStatus()
|
||||
status := item.State.Text()
|
||||
status_emo := item.State.Emoji()
|
||||
hubStatus[itemType][i] = itemHubStatus{
|
||||
Name: item.Name,
|
||||
LocalVersion: item.State.LocalVersion,
|
||||
LocalPath: item.State.LocalPath,
|
||||
Description: item.Description,
|
||||
Status: status,
|
||||
UTF8Status: fmt.Sprintf("%v %s", emo, status),
|
||||
UTF8Status: fmt.Sprintf("%v %s", status_emo, status),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -107,10 +116,9 @@ func listItems(out io.Writer, itemTypes []string, items map[string][]*cwhub.Item
|
|||
|
||||
for _, itemType := range itemTypes {
|
||||
for _, item := range items[itemType] {
|
||||
status, _ := item.InstallStatus()
|
||||
row := []string{
|
||||
item.Name,
|
||||
status,
|
||||
item.State.Text(),
|
||||
item.State.LocalVersion,
|
||||
item.Description,
|
||||
}
|
||||
|
|
|
@ -140,7 +140,7 @@ func collectHubItems(hub *cwhub.Hub, itemType string) []byte {
|
|||
log.Warnf("could not collect %s list: %s", itemType, err)
|
||||
}
|
||||
|
||||
if err := listItems(out, []string{itemType}, items); err != nil {
|
||||
if err := listItems(out, []string{itemType}, items, false); err != nil {
|
||||
log.Warnf("could not collect %s list: %s", itemType, err)
|
||||
}
|
||||
return out.Bytes()
|
||||
|
|
|
@ -18,8 +18,8 @@ func listHubItemTable(out io.Writer, title string, items []*cwhub.Item) {
|
|||
t.SetAlignment(table.AlignLeft, table.AlignLeft, table.AlignLeft, table.AlignLeft)
|
||||
|
||||
for _, item := range items {
|
||||
status, emo := item.InstallStatus()
|
||||
t.AddRow(item.Name, fmt.Sprintf("%v %s", emo, status), item.State.LocalVersion, item.State.LocalPath)
|
||||
status := fmt.Sprintf("%v %s", item.State.Emoji(), item.State.Text())
|
||||
t.AddRow(item.Name, status, item.State.LocalVersion, item.State.LocalPath)
|
||||
}
|
||||
renderTableTitle(out, title)
|
||||
t.Render()
|
||||
|
|
|
@ -262,10 +262,6 @@ func LoadConfig(configFile string, disableAgent bool, disableAPI bool, quiet boo
|
|||
return nil, errors.New("You must run at least the API Server or crowdsec")
|
||||
}
|
||||
|
||||
if flags.TestMode && !cConfig.DisableAgent {
|
||||
cConfig.Crowdsec.LintOnly = true
|
||||
}
|
||||
|
||||
if flags.OneShotDSN != "" && flags.SingleFileType == "" {
|
||||
return nil, errors.New("-dsn requires a -type argument")
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ type CrowdsecServiceCfg struct {
|
|||
BucketsRoutinesCount int `yaml:"buckets_routines"`
|
||||
OutputRoutinesCount int `yaml:"output_routines"`
|
||||
SimulationConfig *SimulationConfig `yaml:"-"`
|
||||
LintOnly bool `yaml:"-"` // if set to true, exit after loading configs
|
||||
BucketStateFile string `yaml:"state_input_file,omitempty"` // if we need to unserialize buckets at start
|
||||
BucketStateDumpDir string `yaml:"state_output_dir,omitempty"` // if we need to unserialize buckets on shutdown
|
||||
BucketsGCEnabled bool `yaml:"-"` // we need to garbage collect buckets when in forensic mode
|
||||
|
|
|
@ -109,7 +109,7 @@ func (h *Hub) ItemStats() []string {
|
|||
loaded += fmt.Sprintf("%d %s, ", len(h.GetItemMap(itemType)), itemType)
|
||||
|
||||
for _, item := range h.GetItemMap(itemType) {
|
||||
if item.IsLocal() {
|
||||
if item.State.IsLocal() {
|
||||
local++
|
||||
}
|
||||
|
||||
|
|
|
@ -53,6 +53,48 @@ type ItemState struct {
|
|||
BelongsToCollections []string `json:"belongs_to_collections,omitempty" yaml:"belongs_to_collections,omitempty"`
|
||||
}
|
||||
|
||||
// IsLocal returns true if the item has been create by a user (not downloaded from the hub).
|
||||
func (s *ItemState) IsLocal() bool {
|
||||
return s.Installed && !s.Downloaded
|
||||
}
|
||||
|
||||
// Text returns the status of the item as a string (eg. "enabled,update-available").
|
||||
func (s *ItemState) Text() string {
|
||||
ret := "disabled"
|
||||
|
||||
if s.Installed {
|
||||
ret = "enabled"
|
||||
}
|
||||
|
||||
if s.IsLocal() {
|
||||
ret += ",local"
|
||||
}
|
||||
|
||||
if s.Tainted {
|
||||
ret += ",tainted"
|
||||
} else if !s.UpToDate && !s.IsLocal() {
|
||||
ret += ",update-available"
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// Emoji returns the status of the item as an emoji (eg. emoji.Warning).
|
||||
func (s *ItemState) Emoji() emoji.Emoji {
|
||||
switch {
|
||||
case s.IsLocal():
|
||||
return emoji.House
|
||||
case !s.Installed:
|
||||
return emoji.Prohibited
|
||||
case s.Tainted || (!s.UpToDate && !s.IsLocal()):
|
||||
return emoji.Warning
|
||||
case s.Installed:
|
||||
return emoji.CheckMark
|
||||
default:
|
||||
return emoji.QuestionMark
|
||||
}
|
||||
}
|
||||
|
||||
// Item is created from an index file and enriched with local info.
|
||||
type Item struct {
|
||||
hub *Hub // back pointer to the hub, to retrieve other items and call install/remove methods
|
||||
|
@ -107,11 +149,6 @@ func (i *Item) HasSubItems() bool {
|
|||
return i.Type == COLLECTIONS
|
||||
}
|
||||
|
||||
// IsLocal returns true if the item has been create by a user (not downloaded from the hub).
|
||||
func (i *Item) IsLocal() bool {
|
||||
return i.State.Installed && !i.State.Downloaded
|
||||
}
|
||||
|
||||
// MarshalJSON is used to prepare the output for "cscli ... inspect -o json".
|
||||
// It must not use a pointer receiver.
|
||||
func (i Item) MarshalJSON() ([]byte, error) {
|
||||
|
@ -139,7 +176,7 @@ func (i Item) MarshalJSON() ([]byte, error) {
|
|||
UpToDate: i.State.UpToDate,
|
||||
Tainted: i.State.Tainted,
|
||||
BelongsToCollections: i.State.BelongsToCollections,
|
||||
Local: i.IsLocal(),
|
||||
Local: i.State.IsLocal(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -155,7 +192,7 @@ func (i Item) MarshalYAML() (interface{}, error) {
|
|||
}{
|
||||
Alias: Alias(i),
|
||||
State: i.State,
|
||||
Local: i.IsLocal(),
|
||||
Local: i.State.IsLocal(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -290,48 +327,6 @@ func (i *Item) descendants() ([]*Item, error) {
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
// InstallStatus returns the status of the item as a string and an emoji
|
||||
// (eg. "enabled,update-available" and emoji.Warning).
|
||||
func (i *Item) InstallStatus() (string, emoji.Emoji) {
|
||||
status := "disabled"
|
||||
ok := false
|
||||
|
||||
if i.State.Installed {
|
||||
ok = true
|
||||
status = "enabled"
|
||||
}
|
||||
|
||||
managed := true
|
||||
if i.IsLocal() {
|
||||
managed = false
|
||||
status += ",local"
|
||||
}
|
||||
|
||||
warning := false
|
||||
if i.State.Tainted {
|
||||
warning = true
|
||||
status += ",tainted"
|
||||
} else if !i.State.UpToDate && !i.IsLocal() {
|
||||
warning = true
|
||||
status += ",update-available"
|
||||
}
|
||||
|
||||
emo := emoji.QuestionMark
|
||||
|
||||
switch {
|
||||
case !managed:
|
||||
emo = emoji.House
|
||||
case !i.State.Installed:
|
||||
emo = emoji.Prohibited
|
||||
case warning:
|
||||
emo = emoji.Warning
|
||||
case ok:
|
||||
emo = emoji.CheckMark
|
||||
}
|
||||
|
||||
return status, emo
|
||||
}
|
||||
|
||||
// versionStatus returns the status of the item version compared to the hub version.
|
||||
// semver requires the 'v' prefix.
|
||||
func (i *Item) versionStatus() int {
|
||||
|
|
|
@ -23,7 +23,7 @@ func TestItemStatus(t *testing.T) {
|
|||
item.State.Tainted = false
|
||||
item.State.Downloaded = true
|
||||
|
||||
txt, _ := item.InstallStatus()
|
||||
txt := item.State.Text()
|
||||
require.Equal(t, "enabled,update-available", txt)
|
||||
|
||||
item.State.Installed = true
|
||||
|
@ -31,7 +31,7 @@ func TestItemStatus(t *testing.T) {
|
|||
item.State.Tainted = false
|
||||
item.State.Downloaded = false
|
||||
|
||||
txt, _ = item.InstallStatus()
|
||||
txt = item.State.Text()
|
||||
require.Equal(t, "enabled,local", txt)
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ func (i *Item) enable() error {
|
|||
return fmt.Errorf("%s is tainted, won't enable unless --force", i.Name)
|
||||
}
|
||||
|
||||
if i.IsLocal() {
|
||||
if i.State.IsLocal() {
|
||||
return fmt.Errorf("%s is local, won't enable", i.Name)
|
||||
}
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ func (i *Item) disable(purge bool, force bool) (bool, error) {
|
|||
|
||||
// Remove disables the item, optionally removing the downloaded content.
|
||||
func (i *Item) Remove(purge bool, force bool) (bool, error) {
|
||||
if i.IsLocal() {
|
||||
if i.State.IsLocal() {
|
||||
log.Warningf("%s is a local item, please delete manually", i.Name)
|
||||
return false, nil
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ import (
|
|||
func (i *Item) Upgrade(force bool) (bool, error) {
|
||||
updated := false
|
||||
|
||||
if i.IsLocal() {
|
||||
if i.State.IsLocal() {
|
||||
log.Infof("not upgrading %s: local item", i.Name)
|
||||
return false, nil
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ func (i *Item) fetch() ([]byte, error) {
|
|||
|
||||
// download downloads the item from the hub and writes it to the hub directory.
|
||||
func (i *Item) download(overwrite bool) (string, error) {
|
||||
if i.IsLocal() {
|
||||
if i.State.IsLocal() {
|
||||
return "", fmt.Errorf("%s is local, can't download", i.Name)
|
||||
}
|
||||
// if user didn't --force, don't overwrite local, tainted, up-to-date files
|
||||
|
|
|
@ -420,7 +420,7 @@ func (h *Hub) localSync() error {
|
|||
case versionFuture:
|
||||
warnings = append(warnings, fmt.Sprintf("collection %s is in the future (currently:%s, latest:%s)", item.Name, item.State.LocalVersion, item.Version))
|
||||
case versionUnknown:
|
||||
if !item.IsLocal() {
|
||||
if !item.State.IsLocal() {
|
||||
warnings = append(warnings, fmt.Sprintf("collection %s is tainted (latest:%s)", item.Name, item.Version))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,17 +34,19 @@ teardown() {
|
|||
|
||||
# no items
|
||||
rune -0 cscli hub list
|
||||
assert_output --regexp ".*PARSERS.*POSTOVERFLOWS.*SCENARIOS.*COLLECTIONS.*"
|
||||
assert_output "No items to display"
|
||||
rune -0 cscli hub list -o json
|
||||
assert_json '{parsers:[],scenarios:[],collections:[],postoverflows:[]}'
|
||||
rune -0 cscli hub list -o raw
|
||||
assert_output 'name,status,version,description,type'
|
||||
|
||||
# some items
|
||||
# some items: with output=human, show only non-empty tables
|
||||
rune -0 cscli parsers install crowdsecurity/whitelists
|
||||
rune -0 cscli scenarios install crowdsecurity/telnet-bf
|
||||
rune -0 cscli hub list
|
||||
assert_output --regexp ".*PARSERS.*crowdsecurity/whitelists.*POSTOVERFLOWS.*SCENARIOS.*crowdsecurity/telnet-bf.*COLLECTIONS.*"
|
||||
assert_output --regexp ".*PARSERS.*crowdsecurity/whitelists.*SCENARIOS.*crowdsecurity/telnet-bf.*"
|
||||
refute_output --partial 'POSTOVERFLOWS'
|
||||
refute_output --partial 'COLLECTIONS'
|
||||
rune -0 cscli hub list -o json
|
||||
rune -0 jq -e '(.parsers | length == 1) and (.scenarios | length == 1)' <(output)
|
||||
rune -0 cscli hub list -o raw
|
||||
|
|
Loading…
Reference in a new issue