lapi to capi : allow push of tainted/custom/manual decisions (#1154)
* add console command to control signal sharing * modify metrics endpoint to add lastpush Co-authored-by: alteredCoder <kevin@crowdsec.net>
This commit is contained in:
parent
50fb1e3df1
commit
6e92da76ad
36 changed files with 851 additions and 81 deletions
|
@ -2,13 +2,22 @@ package main
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"github.com/crowdsecurity/crowdsec/pkg/apiclient"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/csconfig"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/cwhub"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/cwversion"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/types"
|
||||
"github.com/enescakir/emoji"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
@ -21,12 +30,24 @@ func NewConsoleCmd() *cobra.Command {
|
|||
DisableAutoGenTag: true,
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
if err := csConfig.LoadAPIServer(); err != nil || csConfig.DisableAPI {
|
||||
var fdErr *fs.PathError
|
||||
if errors.As(err, &fdErr) {
|
||||
log.Fatalf("Unable to load Local API : %s", fdErr)
|
||||
} else if err != nil {
|
||||
log.Fatalf("Unable to load required Local API Configuration : %s", err)
|
||||
} else {
|
||||
log.Fatal("Local API is disabled, please run this command on the local API machine")
|
||||
}
|
||||
}
|
||||
if csConfig.DisableAPI {
|
||||
log.Fatal("Local API is disabled, please run this command on the local API machine")
|
||||
}
|
||||
if csConfig.API.Server.OnlineClient == nil {
|
||||
log.Fatalf("no configuration for Central API (CAPI) in '%s'", *csConfig.FilePath)
|
||||
log.Fatalf("No configuration for Central API (CAPI) in '%s'", *csConfig.FilePath)
|
||||
}
|
||||
if csConfig.API.Server.OnlineClient.Credentials == nil {
|
||||
log.Fatal("You must configure Central API (CAPI) with `cscli capi register` before enrolling your instance")
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
@ -48,18 +69,6 @@ After running this command your will need to validate the enrollment in the weba
|
|||
`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
DisableAutoGenTag: true,
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
if err := csConfig.LoadAPIServer(); err != nil || csConfig.DisableAPI {
|
||||
log.Fatal("Local API is disabled, please run this command on the local API machine")
|
||||
}
|
||||
if csConfig.API.Server.OnlineClient == nil {
|
||||
log.Fatalf("no configuration for Central API (CAPI) in '%s'", *csConfig.FilePath)
|
||||
}
|
||||
if csConfig.API.Server.OnlineClient.Credentials == nil {
|
||||
log.Fatal("You must configure Central API (CAPI) with `cscli capi register` before enrolling your instance")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
password := strfmt.Password(csConfig.API.Server.OnlineClient.Credentials.Password)
|
||||
apiURL, err := url.Parse(csConfig.API.Server.OnlineClient.Credentials.URL)
|
||||
|
@ -97,11 +106,193 @@ After running this command your will need to validate the enrollment in the weba
|
|||
if err != nil {
|
||||
log.Fatalf("Could not enroll instance: %s", err)
|
||||
}
|
||||
|
||||
SetConsoleOpts(csconfig.CONSOLE_CONFIGS, true)
|
||||
log.Infof("Enabled tainted&manual alerts sharing, see 'cscli console status'.")
|
||||
log.Infof("Watcher successfully enrolled. Visit https://app.crowdsec.net to accept it.")
|
||||
log.Infof("Please restart crowdsec after accepting the enrollment.")
|
||||
},
|
||||
}
|
||||
cmdEnroll.Flags().StringVarP(&name, "name", "n", "", "Name to display in the console")
|
||||
cmdEnroll.Flags().StringSliceVarP(&tags, "tags", "t", tags, "Tags to display in the console")
|
||||
cmdConsole.AddCommand(cmdEnroll)
|
||||
|
||||
var enableAll, disableAll bool
|
||||
|
||||
cmdEnable := &cobra.Command{
|
||||
Use: "enable [feature-flag]",
|
||||
Short: "Enable a feature flag",
|
||||
Example: "enable alerts-tainted",
|
||||
Long: `
|
||||
Enable given information push to the central API. Allows to empower the console`,
|
||||
ValidArgs: csconfig.CONSOLE_CONFIGS,
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
DisableAutoGenTag: true,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if enableAll {
|
||||
SetConsoleOpts(csconfig.CONSOLE_CONFIGS, true)
|
||||
} else {
|
||||
SetConsoleOpts(args, true)
|
||||
}
|
||||
|
||||
if err := csConfig.API.Server.DumpConsoleConfig(); err != nil {
|
||||
log.Fatalf("failed writing console config : %s", err)
|
||||
}
|
||||
if enableAll {
|
||||
log.Infof("All features have been enabled successfully")
|
||||
} else {
|
||||
log.Infof("%v have been enabled", args)
|
||||
}
|
||||
log.Infof(ReloadMessage())
|
||||
},
|
||||
}
|
||||
cmdEnable.Flags().BoolVarP(&enableAll, "all", "a", false, "Enable all feature flags")
|
||||
cmdConsole.AddCommand(cmdEnable)
|
||||
|
||||
cmdDisable := &cobra.Command{
|
||||
Use: "disable [feature-flag]",
|
||||
Short: "Disable a feature flag",
|
||||
Example: "disable alerts-tainted",
|
||||
Long: `
|
||||
Disable given information push to the central API.`,
|
||||
ValidArgs: csconfig.CONSOLE_CONFIGS,
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
DisableAutoGenTag: true,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if disableAll {
|
||||
SetConsoleOpts(csconfig.CONSOLE_CONFIGS, false)
|
||||
} else {
|
||||
SetConsoleOpts(args, false)
|
||||
}
|
||||
|
||||
if err := csConfig.API.Server.DumpConsoleConfig(); err != nil {
|
||||
log.Fatalf("failed writing console config : %s", err)
|
||||
}
|
||||
if disableAll {
|
||||
log.Infof("All features have been disabled")
|
||||
} else {
|
||||
log.Infof("%v have been disabled", args)
|
||||
}
|
||||
log.Infof(ReloadMessage())
|
||||
},
|
||||
}
|
||||
cmdDisable.Flags().BoolVarP(&disableAll, "all", "a", false, "Enable all feature flags")
|
||||
cmdConsole.AddCommand(cmdDisable)
|
||||
|
||||
cmdConsoleStatus := &cobra.Command{
|
||||
Use: "status [feature-flag]",
|
||||
Short: "Shows status of one or all feature flags",
|
||||
Example: "status alerts-tainted",
|
||||
DisableAutoGenTag: true,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
switch csConfig.Cscli.Output {
|
||||
case "human":
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
|
||||
table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
|
||||
table.SetAlignment(tablewriter.ALIGN_LEFT)
|
||||
table.SetHeader([]string{"Option Name", "Activated", "Description"})
|
||||
for _, option := range csconfig.CONSOLE_CONFIGS {
|
||||
switch option {
|
||||
case csconfig.SEND_CUSTOM_SCENARIOS:
|
||||
activated := string(emoji.CrossMark)
|
||||
if *csConfig.API.Server.ConsoleConfig.ShareCustomScenarios {
|
||||
activated = string(emoji.CheckMarkButton)
|
||||
}
|
||||
table.Append([]string{option, activated, "Send alerts from custom scenarios to the console"})
|
||||
case csconfig.SEND_MANUAL_SCENARIOS:
|
||||
activated := string(emoji.CrossMark)
|
||||
if *csConfig.API.Server.ConsoleConfig.ShareManualDecisions {
|
||||
activated = string(emoji.CheckMarkButton)
|
||||
}
|
||||
table.Append([]string{option, activated, "Send manual decisions to the console"})
|
||||
case csconfig.SEND_TAINTED_SCENARIOS:
|
||||
activated := string(emoji.CrossMark)
|
||||
if *csConfig.API.Server.ConsoleConfig.ShareTaintedScenarios {
|
||||
activated = string(emoji.CheckMarkButton)
|
||||
}
|
||||
table.Append([]string{option, activated, "Send alerts from tainted scenarios to the console"})
|
||||
}
|
||||
}
|
||||
table.Render()
|
||||
case "json":
|
||||
data, err := json.MarshalIndent(csConfig.API.Server.ConsoleConfig, "", " ")
|
||||
if err != nil {
|
||||
log.Fatalf("failed to marshal configuration: %s", err)
|
||||
}
|
||||
fmt.Printf("%s\n", string(data))
|
||||
case "raw":
|
||||
csvwriter := csv.NewWriter(os.Stdout)
|
||||
err := csvwriter.Write([]string{"option", "enabled"})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
rows := [][]string{
|
||||
{"share_manual_decisions", fmt.Sprintf("%t", *csConfig.API.Server.ConsoleConfig.ShareManualDecisions)},
|
||||
{"share_custom", fmt.Sprintf("%t", *csConfig.API.Server.ConsoleConfig.ShareCustomScenarios)},
|
||||
{"share_tainted", fmt.Sprintf("%t", *csConfig.API.Server.ConsoleConfig.ShareTaintedScenarios)},
|
||||
}
|
||||
for _, row := range rows {
|
||||
err = csvwriter.Write(row)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
csvwriter.Flush()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
cmdConsole.AddCommand(cmdConsoleStatus)
|
||||
return cmdConsole
|
||||
}
|
||||
|
||||
func SetConsoleOpts(args []string, wanted bool) {
|
||||
for _, arg := range args {
|
||||
switch arg {
|
||||
case csconfig.SEND_CUSTOM_SCENARIOS:
|
||||
/*for each flag check if it's already set before setting it*/
|
||||
if csConfig.API.Server.ConsoleConfig.ShareCustomScenarios != nil {
|
||||
if *csConfig.API.Server.ConsoleConfig.ShareCustomScenarios == wanted {
|
||||
log.Infof("%s already set to %t", csconfig.SEND_CUSTOM_SCENARIOS, wanted)
|
||||
} else {
|
||||
log.Infof("%s set to %t", csconfig.SEND_CUSTOM_SCENARIOS, wanted)
|
||||
*csConfig.API.Server.ConsoleConfig.ShareCustomScenarios = wanted
|
||||
}
|
||||
} else {
|
||||
log.Infof("%s set to %t", csconfig.SEND_CUSTOM_SCENARIOS, wanted)
|
||||
csConfig.API.Server.ConsoleConfig.ShareCustomScenarios = types.BoolPtr(wanted)
|
||||
}
|
||||
case csconfig.SEND_TAINTED_SCENARIOS:
|
||||
/*for each flag check if it's already set before setting it*/
|
||||
if csConfig.API.Server.ConsoleConfig.ShareTaintedScenarios != nil {
|
||||
if *csConfig.API.Server.ConsoleConfig.ShareTaintedScenarios == wanted {
|
||||
log.Infof("%s already set to %t", csconfig.SEND_TAINTED_SCENARIOS, wanted)
|
||||
} else {
|
||||
log.Infof("%s set to %t", csconfig.SEND_TAINTED_SCENARIOS, wanted)
|
||||
*csConfig.API.Server.ConsoleConfig.ShareTaintedScenarios = wanted
|
||||
}
|
||||
} else {
|
||||
log.Infof("%s set to %t", csconfig.SEND_TAINTED_SCENARIOS, wanted)
|
||||
csConfig.API.Server.ConsoleConfig.ShareTaintedScenarios = types.BoolPtr(wanted)
|
||||
}
|
||||
case csconfig.SEND_MANUAL_SCENARIOS:
|
||||
/*for each flag check if it's already set before setting it*/
|
||||
if csConfig.API.Server.ConsoleConfig.ShareManualDecisions != nil {
|
||||
if *csConfig.API.Server.ConsoleConfig.ShareManualDecisions == wanted {
|
||||
log.Infof("%s already set to %t", csconfig.SEND_MANUAL_SCENARIOS, wanted)
|
||||
} else {
|
||||
log.Infof("%s set to %t", csconfig.SEND_MANUAL_SCENARIOS, wanted)
|
||||
*csConfig.API.Server.ConsoleConfig.ShareManualDecisions = wanted
|
||||
}
|
||||
} else {
|
||||
log.Infof("%s set to %t", csconfig.SEND_MANUAL_SCENARIOS, wanted)
|
||||
csConfig.API.Server.ConsoleConfig.ShareManualDecisions = types.BoolPtr(wanted)
|
||||
}
|
||||
default:
|
||||
log.Fatalf("unknown flag %s", arg)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -37,8 +37,7 @@ func DecisionsToTable(alerts *models.GetAlertsResponse) error {
|
|||
var spamLimit map[string]bool = make(map[string]bool)
|
||||
var skipped = 0
|
||||
|
||||
/*process in reverse order to keep the latest item only*/
|
||||
for aIdx := len(*alerts) - 1; aIdx >= 0; aIdx-- {
|
||||
for aIdx := 0; aIdx < len(*alerts); aIdx++ {
|
||||
alertItem := (*alerts)[aIdx]
|
||||
newDecisions := make([]*models.Decision, 0)
|
||||
for _, decisionItem := range alertItem.Decisions {
|
||||
|
@ -303,7 +302,7 @@ cscli decisions add --scope username --value foobar
|
|||
DisableAutoGenTag: true,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var err error
|
||||
var ip, ipRange string
|
||||
var ipRange string
|
||||
alerts := models.AddAlertsRequest{}
|
||||
origin := "cscli"
|
||||
capacity := int32(0)
|
||||
|
@ -358,7 +357,7 @@ cscli decisions add --scope username --value foobar
|
|||
AsName: empty,
|
||||
AsNumber: empty,
|
||||
Cn: empty,
|
||||
IP: ip,
|
||||
IP: addValue,
|
||||
Range: ipRange,
|
||||
Scope: &addScope,
|
||||
Value: &addValue,
|
||||
|
|
|
@ -41,6 +41,7 @@ api:
|
|||
log_level: info
|
||||
listen_uri: 127.0.0.1:8080
|
||||
profiles_path: /etc/crowdsec/profiles.yaml
|
||||
console_path: /etc/crowdsec/console_config.yaml
|
||||
online_client: # Central API credentials (to push signals and receive bad IPs)
|
||||
credentials_path: /etc/crowdsec/online_api_credentials.yaml
|
||||
# tls:
|
||||
|
|
3
config/console_config.yaml
Normal file
3
config/console_config.yaml
Normal file
|
@ -0,0 +1,3 @@
|
|||
share_manual_decisions: false
|
||||
share_custom: true
|
||||
share_tainted: true
|
1
debian/rules
vendored
1
debian/rules
vendored
|
@ -47,4 +47,5 @@ override_dh_auto_install:
|
|||
cp config/config.yaml debian/crowdsec/etc/crowdsec/config.yaml
|
||||
cp config/simulation.yaml debian/crowdsec/etc/crowdsec/simulation.yaml
|
||||
cp config/profiles.yaml debian/crowdsec/etc/crowdsec/profiles.yaml
|
||||
cp config/console_config.yaml debian/crowdsec/etc/crowdsec/console_config.yaml
|
||||
cp -a config/patterns debian/crowdsec/etc/crowdsec
|
||||
|
|
2
go.sum
2
go.sum
|
@ -204,6 +204,7 @@ github.com/go-openapi/errors v0.19.9 h1:9SnKdGhiPZHF3ttwFMiCBEb8jQ4IDdrK+5+a0oTy
|
|||
github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
|
||||
github.com/go-openapi/errors v0.20.1 h1:j23mMDtRxMwIobkpId7sWh7Ddcx4ivaoqUbfXx5P+a8=
|
||||
github.com/go-openapi/errors v0.20.1/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
|
||||
github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4=
|
||||
github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=
|
||||
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||
github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||
|
@ -939,6 +940,7 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
|
|||
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
|
|
@ -3,7 +3,8 @@ package apiclient
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/crowdsecurity/crowdsec/pkg/models"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -24,6 +25,10 @@ func (s *SignalService) Add(ctx context.Context, signals *models.AddSignalsReque
|
|||
if err != nil {
|
||||
return nil, resp, errors.Wrap(err, "while performing request")
|
||||
}
|
||||
log.Printf("Signal push response : http %s", resp.Response.Status)
|
||||
if resp.Response.StatusCode != 200 {
|
||||
log.Warnf("Signal push response : http %s", resp.Response.Status)
|
||||
} else {
|
||||
log.Debugf("Signal push response : http %s", resp.Response.Status)
|
||||
}
|
||||
return &response, resp, nil
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ type apic struct {
|
|||
startup bool
|
||||
credentials *csconfig.ApiCredentialsCfg
|
||||
scenarioList []string
|
||||
consoleConfig *csconfig.ConsoleConfig
|
||||
}
|
||||
|
||||
func IsInSlice(a string, b []string) bool {
|
||||
|
@ -75,7 +76,7 @@ func (a *apic) FetchScenariosListFromDB() ([]string, error) {
|
|||
return scenarios, nil
|
||||
}
|
||||
|
||||
func AlertToSignal(alert *models.Alert) *models.AddSignalsRequestItem {
|
||||
func AlertToSignal(alert *models.Alert, scenarioTrust string) *models.AddSignalsRequestItem {
|
||||
return &models.AddSignalsRequestItem{
|
||||
Message: alert.Message,
|
||||
Scenario: alert.Scenario,
|
||||
|
@ -86,21 +87,23 @@ func AlertToSignal(alert *models.Alert) *models.AddSignalsRequestItem {
|
|||
StopAt: alert.StopAt,
|
||||
CreatedAt: alert.CreatedAt,
|
||||
MachineID: alert.MachineID,
|
||||
ScenarioTrust: &scenarioTrust,
|
||||
}
|
||||
}
|
||||
|
||||
func NewAPIC(config *csconfig.OnlineApiClientCfg, dbClient *database.Client) (*apic, error) {
|
||||
func NewAPIC(config *csconfig.OnlineApiClientCfg, dbClient *database.Client, consoleConfig *csconfig.ConsoleConfig) (*apic, error) {
|
||||
var err error
|
||||
ret := &apic{
|
||||
alertToPush: make(chan []*models.Alert),
|
||||
dbClient: dbClient,
|
||||
mu: sync.Mutex{},
|
||||
startup: true,
|
||||
credentials: config.Credentials,
|
||||
pullTomb: tomb.Tomb{},
|
||||
pushTomb: tomb.Tomb{},
|
||||
metricsTomb: tomb.Tomb{},
|
||||
scenarioList: make([]string, 0),
|
||||
alertToPush: make(chan []*models.Alert),
|
||||
dbClient: dbClient,
|
||||
mu: sync.Mutex{},
|
||||
startup: true,
|
||||
credentials: config.Credentials,
|
||||
pullTomb: tomb.Tomb{},
|
||||
pushTomb: tomb.Tomb{},
|
||||
metricsTomb: tomb.Tomb{},
|
||||
scenarioList: make([]string, 0),
|
||||
consoleConfig: consoleConfig,
|
||||
}
|
||||
|
||||
ret.pullInterval, err = time.ParseDuration(PullInterval)
|
||||
|
@ -167,20 +170,39 @@ func (a *apic) Push() error {
|
|||
case alerts := <-a.alertToPush:
|
||||
var signals []*models.AddSignalsRequestItem
|
||||
for _, alert := range alerts {
|
||||
/*we're only interested into decisions coming from scenarios of the hub*/
|
||||
if alert.ScenarioHash == nil || *alert.ScenarioHash == "" {
|
||||
continue
|
||||
}
|
||||
/*and we're not interested into tainted scenarios neither*/
|
||||
if alert.ScenarioVersion == nil || *alert.ScenarioVersion == "" || *alert.ScenarioVersion == "?" {
|
||||
continue
|
||||
}
|
||||
/*we also ignore alerts in simulated mode*/
|
||||
if *alert.Simulated {
|
||||
log.Debugf("simulation enabled for alert (id:%d), will not be sent to CAPI", alert.ID)
|
||||
continue
|
||||
}
|
||||
signals = append(signals, AlertToSignal(alert))
|
||||
scenarioTrust := "certified"
|
||||
if alert.ScenarioHash == nil || *alert.ScenarioHash == "" {
|
||||
scenarioTrust = "custom"
|
||||
} else if alert.ScenarioVersion == nil || *alert.ScenarioVersion == "" || *alert.ScenarioVersion == "?" {
|
||||
scenarioTrust = "tainted"
|
||||
}
|
||||
if len(alert.Decisions) > 0 {
|
||||
if *alert.Decisions[0].Origin == "cscli" {
|
||||
scenarioTrust = "manual"
|
||||
}
|
||||
}
|
||||
switch scenarioTrust {
|
||||
case "manual":
|
||||
if !*a.consoleConfig.ShareManualDecisions {
|
||||
log.Debugf("manual decision generated an alert, doesn't send it to CAPI because options is disabled")
|
||||
continue
|
||||
}
|
||||
case "tainted":
|
||||
if !*a.consoleConfig.ShareTaintedScenarios {
|
||||
log.Debugf("tainted scenario generated an alert, doesn't send it to CAPI because options is disabled")
|
||||
continue
|
||||
}
|
||||
case "custom":
|
||||
if !*a.consoleConfig.ShareCustomScenarios {
|
||||
log.Debugf("custom scenario generated an alert, doesn't send it to CAPI because options is disabled")
|
||||
continue
|
||||
}
|
||||
}
|
||||
signals = append(signals, AlertToSignal(alert, scenarioTrust))
|
||||
}
|
||||
a.mu.Lock()
|
||||
cache = append(cache, signals...)
|
||||
|
@ -477,8 +499,8 @@ func (a *apic) GetMetrics() (*models.Metrics, error) {
|
|||
version := cwversion.VersionStr()
|
||||
metric := &models.Metrics{
|
||||
ApilVersion: &version,
|
||||
Machines: make([]*models.MetricsSoftInfo, 0),
|
||||
Bouncers: make([]*models.MetricsSoftInfo, 0),
|
||||
Machines: make([]*models.MetricsAgentInfo, 0),
|
||||
Bouncers: make([]*models.MetricsBouncerInfo, 0),
|
||||
}
|
||||
machines, err := a.dbClient.ListMachines()
|
||||
if err != nil {
|
||||
|
@ -489,17 +511,21 @@ func (a *apic) GetMetrics() (*models.Metrics, error) {
|
|||
return metric, err
|
||||
}
|
||||
for _, machine := range machines {
|
||||
m := &models.MetricsSoftInfo{
|
||||
Version: machine.Version,
|
||||
Name: machine.MachineId,
|
||||
m := &models.MetricsAgentInfo{
|
||||
Version: machine.Version,
|
||||
Name: machine.MachineId,
|
||||
LastUpdate: machine.UpdatedAt.String(),
|
||||
LastPush: machine.LastPush.String(),
|
||||
}
|
||||
metric.Machines = append(metric.Machines, m)
|
||||
}
|
||||
|
||||
for _, bouncer := range bouncers {
|
||||
m := &models.MetricsSoftInfo{
|
||||
Version: bouncer.Version,
|
||||
Name: bouncer.Type,
|
||||
m := &models.MetricsBouncerInfo{
|
||||
Version: bouncer.Version,
|
||||
CustomName: bouncer.Name,
|
||||
Name: bouncer.Type,
|
||||
LastPull: bouncer.LastPull.String(),
|
||||
}
|
||||
metric.Bouncers = append(metric.Bouncers, m)
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ type APIServer struct {
|
|||
httpServer *http.Server
|
||||
apic *apic
|
||||
httpServerTomb tomb.Tomb
|
||||
consoleConfig *csconfig.ConsoleConfig
|
||||
}
|
||||
|
||||
// RecoveryWithWriter returns a middleware for a given writer that recovers from any panics and writes a 500 if there was one.
|
||||
|
@ -165,19 +166,21 @@ func NewServer(config *csconfig.LocalApiServerCfg) (*APIServer, error) {
|
|||
return
|
||||
})
|
||||
router.Use(CustomRecoveryWithWriter())
|
||||
|
||||
controller := &controllers.Controller{
|
||||
DBClient: dbClient,
|
||||
Ectx: context.Background(),
|
||||
Router: router,
|
||||
Profiles: config.Profiles,
|
||||
Log: clog,
|
||||
DBClient: dbClient,
|
||||
Ectx: context.Background(),
|
||||
Router: router,
|
||||
Profiles: config.Profiles,
|
||||
Log: clog,
|
||||
ConsoleConfig: config.ConsoleConfig,
|
||||
}
|
||||
|
||||
var apiClient *apic
|
||||
|
||||
if config.OnlineClient != nil && config.OnlineClient.Credentials != nil {
|
||||
log.Printf("Loading CAPI pusher")
|
||||
apiClient, err = NewAPIC(config.OnlineClient, dbClient)
|
||||
apiClient, err = NewAPIC(config.OnlineClient, dbClient, config.ConsoleConfig)
|
||||
if err != nil {
|
||||
return &APIServer{}, err
|
||||
}
|
||||
|
@ -197,6 +200,7 @@ func NewServer(config *csconfig.LocalApiServerCfg) (*APIServer, error) {
|
|||
router: router,
|
||||
apic: apiClient,
|
||||
httpServerTomb: tomb.Tomb{},
|
||||
consoleConfig: config.ConsoleConfig,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
|
|
@ -49,6 +49,11 @@ func LoadTestConfig() csconfig.Config {
|
|||
ListenURI: "http://127.0.0.1:8080",
|
||||
DbConfig: &dbconfig,
|
||||
ProfilesPath: "./tests/profiles.yaml",
|
||||
ConsoleConfig: &csconfig.ConsoleConfig{
|
||||
ShareManualDecisions: new(bool),
|
||||
ShareTaintedScenarios: new(bool),
|
||||
ShareCustomScenarios: new(bool),
|
||||
},
|
||||
}
|
||||
apiConfig := csconfig.APICfg{
|
||||
Server: &apiServerConfig,
|
||||
|
@ -76,6 +81,11 @@ func LoadTestConfigForwardedFor() csconfig.Config {
|
|||
DbConfig: &dbconfig,
|
||||
ProfilesPath: "./tests/profiles.yaml",
|
||||
UseForwardedForHeaders: true,
|
||||
ConsoleConfig: &csconfig.ConsoleConfig{
|
||||
ShareManualDecisions: new(bool),
|
||||
ShareTaintedScenarios: new(bool),
|
||||
ShareCustomScenarios: new(bool),
|
||||
},
|
||||
}
|
||||
apiConfig := csconfig.APICfg{
|
||||
Server: &apiServerConfig,
|
||||
|
|
|
@ -2,6 +2,8 @@ package controllers
|
|||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/alexliesenfeld/health"
|
||||
v1 "github.com/crowdsecurity/crowdsec/pkg/apiserver/controllers/v1"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/csconfig"
|
||||
|
@ -10,7 +12,6 @@ import (
|
|||
"github.com/crowdsecurity/crowdsec/pkg/models"
|
||||
"github.com/gin-gonic/gin"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Controller struct {
|
||||
|
@ -21,6 +22,7 @@ type Controller struct {
|
|||
CAPIChan chan []*models.Alert
|
||||
PluginChannel chan csplugin.ProfileAlert
|
||||
Log *log.Logger
|
||||
ConsoleConfig *csconfig.ConsoleConfig
|
||||
}
|
||||
|
||||
func (c *Controller) Init() error {
|
||||
|
@ -51,7 +53,7 @@ func serveHealth() http.HandlerFunc {
|
|||
}
|
||||
|
||||
func (c *Controller) NewV1() error {
|
||||
handlerV1, err := v1.New(c.DBClient, c.Ectx, c.Profiles, c.CAPIChan, c.PluginChannel)
|
||||
handlerV1, err := v1.New(c.DBClient, c.Ectx, c.Profiles, c.CAPIChan, c.PluginChannel, *c.ConsoleConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -156,10 +156,14 @@ func (c *Controller) CreateAlert(gctx *gin.Context) {
|
|||
gctx.JSON(http.StatusInternalServerError, gin.H{"message": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if !matched {
|
||||
continue
|
||||
}
|
||||
alert.Decisions = append(alert.Decisions, profileDecisions...)
|
||||
|
||||
if len(alert.Decisions) == 0 { // non manual decision
|
||||
alert.Decisions = append(alert.Decisions, profileDecisions...)
|
||||
}
|
||||
profileAlert := *alert
|
||||
c.sendAlertToPluginChannel(&profileAlert, uint(pIdx))
|
||||
if profile.OnSuccess == "break" {
|
||||
|
|
|
@ -18,9 +18,10 @@ type Controller struct {
|
|||
Profiles []*csconfig.ProfileCfg
|
||||
CAPIChan chan []*models.Alert
|
||||
PluginChannel chan csplugin.ProfileAlert
|
||||
ConsoleConfig csconfig.ConsoleConfig
|
||||
}
|
||||
|
||||
func New(dbClient *database.Client, ctx context.Context, profiles []*csconfig.ProfileCfg, capiChan chan []*models.Alert, pluginChannel chan csplugin.ProfileAlert) (*Controller, error) {
|
||||
func New(dbClient *database.Client, ctx context.Context, profiles []*csconfig.ProfileCfg, capiChan chan []*models.Alert, pluginChannel chan csplugin.ProfileAlert, consoleConfig csconfig.ConsoleConfig) (*Controller, error) {
|
||||
var err error
|
||||
v1 := &Controller{
|
||||
Ectx: ctx,
|
||||
|
@ -29,6 +30,7 @@ func New(dbClient *database.Client, ctx context.Context, profiles []*csconfig.Pr
|
|||
Profiles: profiles,
|
||||
CAPIChan: capiChan,
|
||||
PluginChannel: pluginChannel,
|
||||
ConsoleConfig: consoleConfig,
|
||||
}
|
||||
v1.Middlewares, err = middlewares.NewMiddlewares(dbClient)
|
||||
if err != nil {
|
||||
|
|
|
@ -85,6 +85,8 @@ type LocalApiServerCfg struct {
|
|||
LogMedia string `yaml:"-"`
|
||||
OnlineClient *OnlineApiClientCfg `yaml:"online_client"`
|
||||
ProfilesPath string `yaml:"profiles_path,omitempty"`
|
||||
ConsoleConfigPath string `yaml:"console_path,omitempty"`
|
||||
ConsoleConfig *ConsoleConfig `yaml:"-"`
|
||||
Profiles []*ProfileCfg `yaml:"-"`
|
||||
LogLevel *log.Level `yaml:"log_level"`
|
||||
UseForwardedForHeaders bool `yaml:"use_forwarded_for_headers,omitempty"`
|
||||
|
@ -114,6 +116,13 @@ func (c *Config) LoadAPIServer() error {
|
|||
if err := c.API.Server.LoadProfiles(); err != nil {
|
||||
return errors.Wrap(err, "while loading profiles for LAPI")
|
||||
}
|
||||
if c.API.Server.ConsoleConfigPath == "" {
|
||||
c.API.Server.ConsoleConfigPath = DefaultConsoleConfgFilePath
|
||||
}
|
||||
if err := c.API.Server.LoadConsoleConfig(); err != nil {
|
||||
return errors.Wrap(err, "while loading console options")
|
||||
}
|
||||
|
||||
if c.API.Server.OnlineClient != nil && c.API.Server.OnlineClient.CredentialsFilePath != "" {
|
||||
if err := c.API.Server.OnlineClient.Load(); err != nil {
|
||||
return errors.Wrap(err, "loading online client credentials")
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/crowdsecurity/crowdsec/pkg/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
@ -206,6 +207,12 @@ func TestLoadAPIServer(t *testing.T) {
|
|||
DbPath: "./tests/test.db",
|
||||
Type: "sqlite",
|
||||
},
|
||||
ConsoleConfigPath: "/etc/crowdsec/console_config.yaml",
|
||||
ConsoleConfig: &ConsoleConfig{
|
||||
ShareManualDecisions: types.BoolPtr(false),
|
||||
ShareTaintedScenarios: types.BoolPtr(true),
|
||||
ShareCustomScenarios: types.BoolPtr(true),
|
||||
},
|
||||
LogDir: LogDirFullPath,
|
||||
LogMedia: "stdout",
|
||||
OnlineClient: &OnlineApiClientCfg{
|
||||
|
|
83
pkg/csconfig/console.go
Normal file
83
pkg/csconfig/console.go
Normal file
|
@ -0,0 +1,83 @@
|
|||
package csconfig
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/crowdsecurity/crowdsec/pkg/types"
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
const (
|
||||
SEND_CUSTOM_SCENARIOS = "custom"
|
||||
SEND_TAINTED_SCENARIOS = "tainted"
|
||||
SEND_MANUAL_SCENARIOS = "manual"
|
||||
)
|
||||
|
||||
var DefaultConsoleConfgFilePath = "/etc/crowdsec/console_config.yaml"
|
||||
|
||||
var CONSOLE_CONFIGS = []string{SEND_CUSTOM_SCENARIOS, SEND_MANUAL_SCENARIOS, SEND_TAINTED_SCENARIOS}
|
||||
|
||||
type ConsoleConfig struct {
|
||||
ShareManualDecisions *bool `yaml:"share_manual_decisions"`
|
||||
ShareTaintedScenarios *bool `yaml:"share_tainted"`
|
||||
ShareCustomScenarios *bool `yaml:"share_custom"`
|
||||
}
|
||||
|
||||
func (c *LocalApiServerCfg) LoadConsoleConfig() error {
|
||||
c.ConsoleConfig = &ConsoleConfig{}
|
||||
if _, err := os.Stat(c.ConsoleConfigPath); err != nil && os.IsNotExist(err) {
|
||||
log.Debugf("no console configuration to load")
|
||||
c.ConsoleConfig.ShareCustomScenarios = types.BoolPtr(true)
|
||||
c.ConsoleConfig.ShareTaintedScenarios = types.BoolPtr(true)
|
||||
c.ConsoleConfig.ShareManualDecisions = types.BoolPtr(false)
|
||||
return nil
|
||||
}
|
||||
|
||||
yamlFile, err := ioutil.ReadFile(c.ConsoleConfigPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("reading console config file '%s': %s", c.ConsoleConfigPath, err)
|
||||
}
|
||||
err = yaml.Unmarshal(yamlFile, c.ConsoleConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unmarshaling console config file '%s': %s", c.ConsoleConfigPath, err)
|
||||
}
|
||||
|
||||
if c.ConsoleConfig.ShareCustomScenarios == nil {
|
||||
log.Debugf("no share_custom scenarios found, setting to true")
|
||||
c.ConsoleConfig.ShareCustomScenarios = types.BoolPtr(true)
|
||||
}
|
||||
if c.ConsoleConfig.ShareTaintedScenarios == nil {
|
||||
log.Debugf("no share_tainted scenarios found, setting to true")
|
||||
c.ConsoleConfig.ShareTaintedScenarios = types.BoolPtr(true)
|
||||
}
|
||||
if c.ConsoleConfig.ShareManualDecisions == nil {
|
||||
log.Debugf("no share_manual scenarios found, setting to false")
|
||||
c.ConsoleConfig.ShareManualDecisions = types.BoolPtr(false)
|
||||
}
|
||||
log.Debugf("Console configuration '%s' loaded successfully", c.ConsoleConfigPath)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *LocalApiServerCfg) DumpConsoleConfig() error {
|
||||
var out []byte
|
||||
var err error
|
||||
|
||||
if out, err = yaml.Marshal(c.ConsoleConfig); err != nil {
|
||||
return errors.Wrapf(err, "while marshaling ConsoleConfig (for %s)", c.ConsoleConfigPath)
|
||||
}
|
||||
if c.ConsoleConfigPath == "" {
|
||||
log.Debugf("Empty console_path, defaulting to %s", DefaultConsoleConfgFilePath)
|
||||
c.ConsoleConfigPath = DefaultConsoleConfgFilePath
|
||||
}
|
||||
|
||||
if err := os.WriteFile(c.ConsoleConfigPath, out, 0600); err != nil {
|
||||
return errors.Wrapf(err, "while dumping console config to %s", c.ConsoleConfigPath)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -15,7 +15,6 @@ import (
|
|||
|
||||
func BuildDecisionRequestWithFilter(query *ent.DecisionQuery, filter map[string][]string) (*ent.DecisionQuery, error) {
|
||||
|
||||
//func BuildDecisionRequestWithFilter(query *ent.Query, filter map[string][]string) (*ent.DecisionQuery, error) {
|
||||
var err error
|
||||
var start_ip, start_sfx, end_ip, end_sfx int64
|
||||
var ip_sz int
|
||||
|
|
|
@ -20,6 +20,8 @@ type Machine struct {
|
|||
CreatedAt time.Time `json:"created_at,omitempty"`
|
||||
// UpdatedAt holds the value of the "updated_at" field.
|
||||
UpdatedAt time.Time `json:"updated_at,omitempty"`
|
||||
// LastPush holds the value of the "last_push" field.
|
||||
LastPush time.Time `json:"last_push,omitempty"`
|
||||
// MachineId holds the value of the "machineId" field.
|
||||
MachineId string `json:"machineId,omitempty"`
|
||||
// Password holds the value of the "password" field.
|
||||
|
@ -68,7 +70,7 @@ func (*Machine) scanValues(columns []string) ([]interface{}, error) {
|
|||
values[i] = new(sql.NullInt64)
|
||||
case machine.FieldMachineId, machine.FieldPassword, machine.FieldIpAddress, machine.FieldScenarios, machine.FieldVersion, machine.FieldStatus:
|
||||
values[i] = new(sql.NullString)
|
||||
case machine.FieldCreatedAt, machine.FieldUpdatedAt:
|
||||
case machine.FieldCreatedAt, machine.FieldUpdatedAt, machine.FieldLastPush:
|
||||
values[i] = new(sql.NullTime)
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected column %q for type Machine", columns[i])
|
||||
|
@ -103,6 +105,12 @@ func (m *Machine) assignValues(columns []string, values []interface{}) error {
|
|||
} else if value.Valid {
|
||||
m.UpdatedAt = value.Time
|
||||
}
|
||||
case machine.FieldLastPush:
|
||||
if value, ok := values[i].(*sql.NullTime); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field last_push", values[i])
|
||||
} else if value.Valid {
|
||||
m.LastPush = value.Time
|
||||
}
|
||||
case machine.FieldMachineId:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field machineId", values[i])
|
||||
|
@ -182,6 +190,8 @@ func (m *Machine) String() string {
|
|||
builder.WriteString(m.CreatedAt.Format(time.ANSIC))
|
||||
builder.WriteString(", updated_at=")
|
||||
builder.WriteString(m.UpdatedAt.Format(time.ANSIC))
|
||||
builder.WriteString(", last_push=")
|
||||
builder.WriteString(m.LastPush.Format(time.ANSIC))
|
||||
builder.WriteString(", machineId=")
|
||||
builder.WriteString(m.MachineId)
|
||||
builder.WriteString(", password=<sensitive>")
|
||||
|
|
|
@ -15,6 +15,8 @@ const (
|
|||
FieldCreatedAt = "created_at"
|
||||
// FieldUpdatedAt holds the string denoting the updated_at field in the database.
|
||||
FieldUpdatedAt = "updated_at"
|
||||
// FieldLastPush holds the string denoting the last_push field in the database.
|
||||
FieldLastPush = "last_push"
|
||||
// FieldMachineId holds the string denoting the machineid field in the database.
|
||||
FieldMachineId = "machine_id"
|
||||
// FieldPassword holds the string denoting the password field in the database.
|
||||
|
@ -47,6 +49,7 @@ var Columns = []string{
|
|||
FieldID,
|
||||
FieldCreatedAt,
|
||||
FieldUpdatedAt,
|
||||
FieldLastPush,
|
||||
FieldMachineId,
|
||||
FieldPassword,
|
||||
FieldIpAddress,
|
||||
|
@ -71,6 +74,8 @@ var (
|
|||
DefaultCreatedAt func() time.Time
|
||||
// DefaultUpdatedAt holds the default value on creation for the "updated_at" field.
|
||||
DefaultUpdatedAt func() time.Time
|
||||
// DefaultLastPush holds the default value on creation for the "last_push" field.
|
||||
DefaultLastPush func() time.Time
|
||||
// ScenariosValidator is a validator for the "scenarios" field. It is called by the builders before save.
|
||||
ScenariosValidator func(string) error
|
||||
// DefaultIsValidated holds the default value on creation for the "isValidated" field.
|
||||
|
|
|
@ -107,6 +107,13 @@ func UpdatedAt(v time.Time) predicate.Machine {
|
|||
})
|
||||
}
|
||||
|
||||
// LastPush applies equality check predicate on the "last_push" field. It's identical to LastPushEQ.
|
||||
func LastPush(v time.Time) predicate.Machine {
|
||||
return predicate.Machine(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldLastPush), v))
|
||||
})
|
||||
}
|
||||
|
||||
// MachineId applies equality check predicate on the "machineId" field. It's identical to MachineIdEQ.
|
||||
func MachineId(v string) predicate.Machine {
|
||||
return predicate.Machine(func(s *sql.Selector) {
|
||||
|
@ -308,6 +315,96 @@ func UpdatedAtLTE(v time.Time) predicate.Machine {
|
|||
})
|
||||
}
|
||||
|
||||
// LastPushEQ applies the EQ predicate on the "last_push" field.
|
||||
func LastPushEQ(v time.Time) predicate.Machine {
|
||||
return predicate.Machine(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldLastPush), v))
|
||||
})
|
||||
}
|
||||
|
||||
// LastPushNEQ applies the NEQ predicate on the "last_push" field.
|
||||
func LastPushNEQ(v time.Time) predicate.Machine {
|
||||
return predicate.Machine(func(s *sql.Selector) {
|
||||
s.Where(sql.NEQ(s.C(FieldLastPush), v))
|
||||
})
|
||||
}
|
||||
|
||||
// LastPushIn applies the In predicate on the "last_push" field.
|
||||
func LastPushIn(vs ...time.Time) predicate.Machine {
|
||||
v := make([]interface{}, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.Machine(func(s *sql.Selector) {
|
||||
// if not arguments were provided, append the FALSE constants,
|
||||
// since we can't apply "IN ()". This will make this predicate falsy.
|
||||
if len(v) == 0 {
|
||||
s.Where(sql.False())
|
||||
return
|
||||
}
|
||||
s.Where(sql.In(s.C(FieldLastPush), v...))
|
||||
})
|
||||
}
|
||||
|
||||
// LastPushNotIn applies the NotIn predicate on the "last_push" field.
|
||||
func LastPushNotIn(vs ...time.Time) predicate.Machine {
|
||||
v := make([]interface{}, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.Machine(func(s *sql.Selector) {
|
||||
// if not arguments were provided, append the FALSE constants,
|
||||
// since we can't apply "IN ()". This will make this predicate falsy.
|
||||
if len(v) == 0 {
|
||||
s.Where(sql.False())
|
||||
return
|
||||
}
|
||||
s.Where(sql.NotIn(s.C(FieldLastPush), v...))
|
||||
})
|
||||
}
|
||||
|
||||
// LastPushGT applies the GT predicate on the "last_push" field.
|
||||
func LastPushGT(v time.Time) predicate.Machine {
|
||||
return predicate.Machine(func(s *sql.Selector) {
|
||||
s.Where(sql.GT(s.C(FieldLastPush), v))
|
||||
})
|
||||
}
|
||||
|
||||
// LastPushGTE applies the GTE predicate on the "last_push" field.
|
||||
func LastPushGTE(v time.Time) predicate.Machine {
|
||||
return predicate.Machine(func(s *sql.Selector) {
|
||||
s.Where(sql.GTE(s.C(FieldLastPush), v))
|
||||
})
|
||||
}
|
||||
|
||||
// LastPushLT applies the LT predicate on the "last_push" field.
|
||||
func LastPushLT(v time.Time) predicate.Machine {
|
||||
return predicate.Machine(func(s *sql.Selector) {
|
||||
s.Where(sql.LT(s.C(FieldLastPush), v))
|
||||
})
|
||||
}
|
||||
|
||||
// LastPushLTE applies the LTE predicate on the "last_push" field.
|
||||
func LastPushLTE(v time.Time) predicate.Machine {
|
||||
return predicate.Machine(func(s *sql.Selector) {
|
||||
s.Where(sql.LTE(s.C(FieldLastPush), v))
|
||||
})
|
||||
}
|
||||
|
||||
// LastPushIsNil applies the IsNil predicate on the "last_push" field.
|
||||
func LastPushIsNil() predicate.Machine {
|
||||
return predicate.Machine(func(s *sql.Selector) {
|
||||
s.Where(sql.IsNull(s.C(FieldLastPush)))
|
||||
})
|
||||
}
|
||||
|
||||
// LastPushNotNil applies the NotNil predicate on the "last_push" field.
|
||||
func LastPushNotNil() predicate.Machine {
|
||||
return predicate.Machine(func(s *sql.Selector) {
|
||||
s.Where(sql.NotNull(s.C(FieldLastPush)))
|
||||
})
|
||||
}
|
||||
|
||||
// MachineIdEQ applies the EQ predicate on the "machineId" field.
|
||||
func MachineIdEQ(v string) predicate.Machine {
|
||||
return predicate.Machine(func(s *sql.Selector) {
|
||||
|
|
|
@ -49,6 +49,20 @@ func (mc *MachineCreate) SetNillableUpdatedAt(t *time.Time) *MachineCreate {
|
|||
return mc
|
||||
}
|
||||
|
||||
// SetLastPush sets the "last_push" field.
|
||||
func (mc *MachineCreate) SetLastPush(t time.Time) *MachineCreate {
|
||||
mc.mutation.SetLastPush(t)
|
||||
return mc
|
||||
}
|
||||
|
||||
// SetNillableLastPush sets the "last_push" field if the given value is not nil.
|
||||
func (mc *MachineCreate) SetNillableLastPush(t *time.Time) *MachineCreate {
|
||||
if t != nil {
|
||||
mc.SetLastPush(*t)
|
||||
}
|
||||
return mc
|
||||
}
|
||||
|
||||
// SetMachineId sets the "machineId" field.
|
||||
func (mc *MachineCreate) SetMachineId(s string) *MachineCreate {
|
||||
mc.mutation.SetMachineId(s)
|
||||
|
@ -217,6 +231,10 @@ func (mc *MachineCreate) defaults() {
|
|||
v := machine.DefaultUpdatedAt()
|
||||
mc.mutation.SetUpdatedAt(v)
|
||||
}
|
||||
if _, ok := mc.mutation.LastPush(); !ok {
|
||||
v := machine.DefaultLastPush()
|
||||
mc.mutation.SetLastPush(v)
|
||||
}
|
||||
if _, ok := mc.mutation.IsValidated(); !ok {
|
||||
v := machine.DefaultIsValidated
|
||||
mc.mutation.SetIsValidated(v)
|
||||
|
@ -291,6 +309,14 @@ func (mc *MachineCreate) createSpec() (*Machine, *sqlgraph.CreateSpec) {
|
|||
})
|
||||
_node.UpdatedAt = value
|
||||
}
|
||||
if value, ok := mc.mutation.LastPush(); ok {
|
||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeTime,
|
||||
Value: value,
|
||||
Column: machine.FieldLastPush,
|
||||
})
|
||||
_node.LastPush = value
|
||||
}
|
||||
if value, ok := mc.mutation.MachineId(); ok {
|
||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeString,
|
||||
|
|
|
@ -56,6 +56,26 @@ func (mu *MachineUpdate) SetNillableUpdatedAt(t *time.Time) *MachineUpdate {
|
|||
return mu
|
||||
}
|
||||
|
||||
// SetLastPush sets the "last_push" field.
|
||||
func (mu *MachineUpdate) SetLastPush(t time.Time) *MachineUpdate {
|
||||
mu.mutation.SetLastPush(t)
|
||||
return mu
|
||||
}
|
||||
|
||||
// SetNillableLastPush sets the "last_push" field if the given value is not nil.
|
||||
func (mu *MachineUpdate) SetNillableLastPush(t *time.Time) *MachineUpdate {
|
||||
if t != nil {
|
||||
mu.SetLastPush(*t)
|
||||
}
|
||||
return mu
|
||||
}
|
||||
|
||||
// ClearLastPush clears the value of the "last_push" field.
|
||||
func (mu *MachineUpdate) ClearLastPush() *MachineUpdate {
|
||||
mu.mutation.ClearLastPush()
|
||||
return mu
|
||||
}
|
||||
|
||||
// SetMachineId sets the "machineId" field.
|
||||
func (mu *MachineUpdate) SetMachineId(s string) *MachineUpdate {
|
||||
mu.mutation.SetMachineId(s)
|
||||
|
@ -291,6 +311,19 @@ func (mu *MachineUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
|||
Column: machine.FieldUpdatedAt,
|
||||
})
|
||||
}
|
||||
if value, ok := mu.mutation.LastPush(); ok {
|
||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeTime,
|
||||
Value: value,
|
||||
Column: machine.FieldLastPush,
|
||||
})
|
||||
}
|
||||
if mu.mutation.LastPushCleared() {
|
||||
_spec.Fields.Clear = append(_spec.Fields.Clear, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeTime,
|
||||
Column: machine.FieldLastPush,
|
||||
})
|
||||
}
|
||||
if value, ok := mu.mutation.MachineId(); ok {
|
||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeString,
|
||||
|
@ -459,6 +492,26 @@ func (muo *MachineUpdateOne) SetNillableUpdatedAt(t *time.Time) *MachineUpdateOn
|
|||
return muo
|
||||
}
|
||||
|
||||
// SetLastPush sets the "last_push" field.
|
||||
func (muo *MachineUpdateOne) SetLastPush(t time.Time) *MachineUpdateOne {
|
||||
muo.mutation.SetLastPush(t)
|
||||
return muo
|
||||
}
|
||||
|
||||
// SetNillableLastPush sets the "last_push" field if the given value is not nil.
|
||||
func (muo *MachineUpdateOne) SetNillableLastPush(t *time.Time) *MachineUpdateOne {
|
||||
if t != nil {
|
||||
muo.SetLastPush(*t)
|
||||
}
|
||||
return muo
|
||||
}
|
||||
|
||||
// ClearLastPush clears the value of the "last_push" field.
|
||||
func (muo *MachineUpdateOne) ClearLastPush() *MachineUpdateOne {
|
||||
muo.mutation.ClearLastPush()
|
||||
return muo
|
||||
}
|
||||
|
||||
// SetMachineId sets the "machineId" field.
|
||||
func (muo *MachineUpdateOne) SetMachineId(s string) *MachineUpdateOne {
|
||||
muo.mutation.SetMachineId(s)
|
||||
|
@ -718,6 +771,19 @@ func (muo *MachineUpdateOne) sqlSave(ctx context.Context) (_node *Machine, err e
|
|||
Column: machine.FieldUpdatedAt,
|
||||
})
|
||||
}
|
||||
if value, ok := muo.mutation.LastPush(); ok {
|
||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeTime,
|
||||
Value: value,
|
||||
Column: machine.FieldLastPush,
|
||||
})
|
||||
}
|
||||
if muo.mutation.LastPushCleared() {
|
||||
_spec.Fields.Clear = append(_spec.Fields.Clear, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeTime,
|
||||
Column: machine.FieldLastPush,
|
||||
})
|
||||
}
|
||||
if value, ok := muo.mutation.MachineId(); ok {
|
||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeString,
|
||||
|
|
|
@ -137,6 +137,7 @@ var (
|
|||
{Name: "id", Type: field.TypeInt, Increment: true},
|
||||
{Name: "created_at", Type: field.TypeTime},
|
||||
{Name: "updated_at", Type: field.TypeTime},
|
||||
{Name: "last_push", Type: field.TypeTime, Nullable: true},
|
||||
{Name: "machine_id", Type: field.TypeString, Unique: true},
|
||||
{Name: "password", Type: field.TypeString},
|
||||
{Name: "ip_address", Type: field.TypeString},
|
||||
|
|
|
@ -4986,6 +4986,7 @@ type MachineMutation struct {
|
|||
id *int
|
||||
created_at *time.Time
|
||||
updated_at *time.Time
|
||||
last_push *time.Time
|
||||
machineId *string
|
||||
password *string
|
||||
ipAddress *string
|
||||
|
@ -5153,6 +5154,55 @@ func (m *MachineMutation) ResetUpdatedAt() {
|
|||
m.updated_at = nil
|
||||
}
|
||||
|
||||
// SetLastPush sets the "last_push" field.
|
||||
func (m *MachineMutation) SetLastPush(t time.Time) {
|
||||
m.last_push = &t
|
||||
}
|
||||
|
||||
// LastPush returns the value of the "last_push" field in the mutation.
|
||||
func (m *MachineMutation) LastPush() (r time.Time, exists bool) {
|
||||
v := m.last_push
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// OldLastPush returns the old "last_push" field's value of the Machine entity.
|
||||
// If the Machine object wasn't provided to the builder, the object is fetched from the database.
|
||||
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
||||
func (m *MachineMutation) OldLastPush(ctx context.Context) (v time.Time, err error) {
|
||||
if !m.op.Is(OpUpdateOne) {
|
||||
return v, fmt.Errorf("OldLastPush is only allowed on UpdateOne operations")
|
||||
}
|
||||
if m.id == nil || m.oldValue == nil {
|
||||
return v, fmt.Errorf("OldLastPush requires an ID field in the mutation")
|
||||
}
|
||||
oldValue, err := m.oldValue(ctx)
|
||||
if err != nil {
|
||||
return v, fmt.Errorf("querying old value for OldLastPush: %w", err)
|
||||
}
|
||||
return oldValue.LastPush, nil
|
||||
}
|
||||
|
||||
// ClearLastPush clears the value of the "last_push" field.
|
||||
func (m *MachineMutation) ClearLastPush() {
|
||||
m.last_push = nil
|
||||
m.clearedFields[machine.FieldLastPush] = struct{}{}
|
||||
}
|
||||
|
||||
// LastPushCleared returns if the "last_push" field was cleared in this mutation.
|
||||
func (m *MachineMutation) LastPushCleared() bool {
|
||||
_, ok := m.clearedFields[machine.FieldLastPush]
|
||||
return ok
|
||||
}
|
||||
|
||||
// ResetLastPush resets all changes to the "last_push" field.
|
||||
func (m *MachineMutation) ResetLastPush() {
|
||||
m.last_push = nil
|
||||
delete(m.clearedFields, machine.FieldLastPush)
|
||||
}
|
||||
|
||||
// SetMachineId sets the "machineId" field.
|
||||
func (m *MachineMutation) SetMachineId(s string) {
|
||||
m.machineId = &s
|
||||
|
@ -5517,13 +5567,16 @@ func (m *MachineMutation) Type() string {
|
|||
// order to get all numeric fields that were incremented/decremented, call
|
||||
// AddedFields().
|
||||
func (m *MachineMutation) Fields() []string {
|
||||
fields := make([]string, 0, 9)
|
||||
fields := make([]string, 0, 10)
|
||||
if m.created_at != nil {
|
||||
fields = append(fields, machine.FieldCreatedAt)
|
||||
}
|
||||
if m.updated_at != nil {
|
||||
fields = append(fields, machine.FieldUpdatedAt)
|
||||
}
|
||||
if m.last_push != nil {
|
||||
fields = append(fields, machine.FieldLastPush)
|
||||
}
|
||||
if m.machineId != nil {
|
||||
fields = append(fields, machine.FieldMachineId)
|
||||
}
|
||||
|
@ -5557,6 +5610,8 @@ func (m *MachineMutation) Field(name string) (ent.Value, bool) {
|
|||
return m.CreatedAt()
|
||||
case machine.FieldUpdatedAt:
|
||||
return m.UpdatedAt()
|
||||
case machine.FieldLastPush:
|
||||
return m.LastPush()
|
||||
case machine.FieldMachineId:
|
||||
return m.MachineId()
|
||||
case machine.FieldPassword:
|
||||
|
@ -5584,6 +5639,8 @@ func (m *MachineMutation) OldField(ctx context.Context, name string) (ent.Value,
|
|||
return m.OldCreatedAt(ctx)
|
||||
case machine.FieldUpdatedAt:
|
||||
return m.OldUpdatedAt(ctx)
|
||||
case machine.FieldLastPush:
|
||||
return m.OldLastPush(ctx)
|
||||
case machine.FieldMachineId:
|
||||
return m.OldMachineId(ctx)
|
||||
case machine.FieldPassword:
|
||||
|
@ -5621,6 +5678,13 @@ func (m *MachineMutation) SetField(name string, value ent.Value) error {
|
|||
}
|
||||
m.SetUpdatedAt(v)
|
||||
return nil
|
||||
case machine.FieldLastPush:
|
||||
v, ok := value.(time.Time)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.SetLastPush(v)
|
||||
return nil
|
||||
case machine.FieldMachineId:
|
||||
v, ok := value.(string)
|
||||
if !ok {
|
||||
|
@ -5700,6 +5764,9 @@ func (m *MachineMutation) AddField(name string, value ent.Value) error {
|
|||
// mutation.
|
||||
func (m *MachineMutation) ClearedFields() []string {
|
||||
var fields []string
|
||||
if m.FieldCleared(machine.FieldLastPush) {
|
||||
fields = append(fields, machine.FieldLastPush)
|
||||
}
|
||||
if m.FieldCleared(machine.FieldScenarios) {
|
||||
fields = append(fields, machine.FieldScenarios)
|
||||
}
|
||||
|
@ -5723,6 +5790,9 @@ func (m *MachineMutation) FieldCleared(name string) bool {
|
|||
// error if the field is not defined in the schema.
|
||||
func (m *MachineMutation) ClearField(name string) error {
|
||||
switch name {
|
||||
case machine.FieldLastPush:
|
||||
m.ClearLastPush()
|
||||
return nil
|
||||
case machine.FieldScenarios:
|
||||
m.ClearScenarios()
|
||||
return nil
|
||||
|
@ -5746,6 +5816,9 @@ func (m *MachineMutation) ResetField(name string) error {
|
|||
case machine.FieldUpdatedAt:
|
||||
m.ResetUpdatedAt()
|
||||
return nil
|
||||
case machine.FieldLastPush:
|
||||
m.ResetLastPush()
|
||||
return nil
|
||||
case machine.FieldMachineId:
|
||||
m.ResetMachineId()
|
||||
return nil
|
||||
|
|
|
@ -112,12 +112,16 @@ func init() {
|
|||
machineDescUpdatedAt := machineFields[1].Descriptor()
|
||||
// machine.DefaultUpdatedAt holds the default value on creation for the updated_at field.
|
||||
machine.DefaultUpdatedAt = machineDescUpdatedAt.Default.(func() time.Time)
|
||||
// machineDescLastPush is the schema descriptor for last_push field.
|
||||
machineDescLastPush := machineFields[2].Descriptor()
|
||||
// machine.DefaultLastPush holds the default value on creation for the last_push field.
|
||||
machine.DefaultLastPush = machineDescLastPush.Default.(func() time.Time)
|
||||
// machineDescScenarios is the schema descriptor for scenarios field.
|
||||
machineDescScenarios := machineFields[5].Descriptor()
|
||||
machineDescScenarios := machineFields[6].Descriptor()
|
||||
// machine.ScenariosValidator is a validator for the "scenarios" field. It is called by the builders before save.
|
||||
machine.ScenariosValidator = machineDescScenarios.Validators[0].(func(string) error)
|
||||
// machineDescIsValidated is the schema descriptor for isValidated field.
|
||||
machineDescIsValidated := machineFields[7].Descriptor()
|
||||
machineDescIsValidated := machineFields[8].Descriptor()
|
||||
// machine.DefaultIsValidated holds the default value on creation for the isValidated field.
|
||||
machine.DefaultIsValidated = machineDescIsValidated.Default.(bool)
|
||||
metaFields := schema.Meta{}.Fields()
|
||||
|
|
|
@ -20,6 +20,8 @@ func (Machine) Fields() []ent.Field {
|
|||
Default(time.Now),
|
||||
field.Time("updated_at").
|
||||
Default(time.Now),
|
||||
field.Time("last_push").
|
||||
Default(time.Now).Optional(),
|
||||
field.String("machineId").Unique(),
|
||||
field.String("password").Sensitive(),
|
||||
field.String("ipAddress"),
|
||||
|
|
|
@ -110,6 +110,14 @@ func (c *Client) DeleteWatcher(name string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) UpdateMachineLastPush(machineID string) error {
|
||||
_, err := c.Ent.Machine.Update().Where(machine.MachineIdEQ(machineID)).SetLastPush(time.Now()).Save(c.CTX)
|
||||
if err != nil {
|
||||
return errors.Wrapf(UpdateFail, "updating machine last_push: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) UpdateMachineScenarios(scenarios string, ID int) error {
|
||||
_, err := c.Ent.Machine.UpdateOneID(ID).
|
||||
SetUpdatedAt(time.Now()).
|
||||
|
|
|
@ -37,6 +37,10 @@ type AddSignalsRequestItem struct {
|
|||
// Required: true
|
||||
ScenarioHash *string `json:"scenario_hash"`
|
||||
|
||||
// scenario trust
|
||||
// Required: true
|
||||
ScenarioTrust *string `json:"scenario_trust"`
|
||||
|
||||
// scenario version
|
||||
// Required: true
|
||||
ScenarioVersion *string `json:"scenario_version"`
|
||||
|
@ -70,6 +74,10 @@ func (m *AddSignalsRequestItem) Validate(formats strfmt.Registry) error {
|
|||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validateScenarioTrust(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validateScenarioVersion(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
@ -119,6 +127,15 @@ func (m *AddSignalsRequestItem) validateScenarioHash(formats strfmt.Registry) er
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *AddSignalsRequestItem) validateScenarioTrust(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("scenario_trust", "body", m.ScenarioTrust); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AddSignalsRequestItem) validateScenarioVersion(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("scenario_version", "body", m.ScenarioVersion); err != nil {
|
||||
|
|
|
@ -19,7 +19,7 @@ import (
|
|||
// swagger:model Decision
|
||||
type Decision struct {
|
||||
|
||||
// duration
|
||||
// the duration of the decisions
|
||||
// Required: true
|
||||
Duration *string `json:"duration"`
|
||||
|
||||
|
@ -47,6 +47,9 @@ type Decision struct {
|
|||
// Required: true
|
||||
Type *string `json:"type"`
|
||||
|
||||
// the date until the decisions must be active
|
||||
Until string `json:"until,omitempty"`
|
||||
|
||||
// the value of the decision scope : an IP, a range, a username, etc
|
||||
// Required: true
|
||||
Value *string `json:"value"`
|
||||
|
|
|
@ -777,17 +777,34 @@ definitions:
|
|||
bouncers:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/MetricsSoftInfo'
|
||||
$ref: '#/definitions/MetricsBouncerInfo'
|
||||
machines:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/MetricsSoftInfo'
|
||||
$ref: '#/definitions/MetricsAgentInfo'
|
||||
required:
|
||||
- apil_version
|
||||
- bouncers
|
||||
- machines
|
||||
MetricsSoftInfo:
|
||||
title: MetricsSoftInfo
|
||||
MetricsBouncerInfo:
|
||||
title: MetricsBouncerInfo
|
||||
description: Software version info (so we can warn users about out-of-date software). The software name and the version are "guessed" from the user-agent
|
||||
type: object
|
||||
properties:
|
||||
custom_name:
|
||||
type: string
|
||||
description: name of the component
|
||||
name:
|
||||
type: string
|
||||
description: bouncer type (firewall, php ...)
|
||||
version:
|
||||
type: string
|
||||
description: software version
|
||||
last_pull:
|
||||
type: string
|
||||
description: last bouncer pull date
|
||||
MetricsAgentInfo:
|
||||
title: MetricsAgentInfo
|
||||
description: Software version info (so we can warn users about out-of-date software). The software name and the version are "guessed" from the user-agent
|
||||
type: object
|
||||
properties:
|
||||
|
@ -797,6 +814,12 @@ definitions:
|
|||
version:
|
||||
type: string
|
||||
description: software version
|
||||
last_update:
|
||||
type: string
|
||||
description: last agent update date
|
||||
last_push:
|
||||
type: string
|
||||
description: last agent push date
|
||||
Decision:
|
||||
title: Decision
|
||||
type: object
|
||||
|
@ -818,7 +841,11 @@ definitions:
|
|||
description: 'the value of the decision scope : an IP, a range, a username, etc'
|
||||
type: string
|
||||
duration:
|
||||
description: 'the duration of the decisions'
|
||||
type: string
|
||||
until:
|
||||
type: string
|
||||
description: 'the date until the decisions must be active'
|
||||
scenario:
|
||||
type: string
|
||||
simulated:
|
||||
|
@ -926,6 +953,7 @@ definitions:
|
|||
- "source"
|
||||
- "start_at"
|
||||
- "stop_at"
|
||||
- "scenario_trust"
|
||||
properties:
|
||||
scenario_hash:
|
||||
type: "string"
|
||||
|
@ -939,6 +967,8 @@ definitions:
|
|||
$ref: "#/definitions/Source"
|
||||
scenario_version:
|
||||
type: "string"
|
||||
scenario_trust:
|
||||
type: "string"
|
||||
message:
|
||||
type: "string"
|
||||
description: "a human readable message"
|
||||
|
|
|
@ -26,11 +26,11 @@ type Metrics struct {
|
|||
|
||||
// bouncers
|
||||
// Required: true
|
||||
Bouncers []*MetricsSoftInfo `json:"bouncers"`
|
||||
Bouncers []*MetricsBouncerInfo `json:"bouncers"`
|
||||
|
||||
// machines
|
||||
// Required: true
|
||||
Machines []*MetricsSoftInfo `json:"machines"`
|
||||
Machines []*MetricsAgentInfo `json:"machines"`
|
||||
}
|
||||
|
||||
// Validate validates this metrics
|
||||
|
|
|
@ -12,12 +12,18 @@ import (
|
|||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// MetricsSoftInfo MetricsSoftInfo
|
||||
// MetricsAgentInfo MetricsAgentInfo
|
||||
//
|
||||
// Software version info (so we can warn users about out-of-date software). The software name and the version are "guessed" from the user-agent
|
||||
//
|
||||
// swagger:model MetricsSoftInfo
|
||||
type MetricsSoftInfo struct {
|
||||
// swagger:model MetricsAgentInfo
|
||||
type MetricsAgentInfo struct {
|
||||
|
||||
// last agent push date
|
||||
LastPush string `json:"last_push,omitempty"`
|
||||
|
||||
// last agent update date
|
||||
LastUpdate string `json:"last_update,omitempty"`
|
||||
|
||||
// name of the component
|
||||
Name string `json:"name,omitempty"`
|
||||
|
@ -26,18 +32,18 @@ type MetricsSoftInfo struct {
|
|||
Version string `json:"version,omitempty"`
|
||||
}
|
||||
|
||||
// Validate validates this metrics soft info
|
||||
func (m *MetricsSoftInfo) Validate(formats strfmt.Registry) error {
|
||||
// Validate validates this metrics agent info
|
||||
func (m *MetricsAgentInfo) Validate(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this metrics soft info based on context it is used
|
||||
func (m *MetricsSoftInfo) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
// ContextValidate validates this metrics agent info based on context it is used
|
||||
func (m *MetricsAgentInfo) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *MetricsSoftInfo) MarshalBinary() ([]byte, error) {
|
||||
func (m *MetricsAgentInfo) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -45,8 +51,8 @@ func (m *MetricsSoftInfo) MarshalBinary() ([]byte, error) {
|
|||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *MetricsSoftInfo) UnmarshalBinary(b []byte) error {
|
||||
var res MetricsSoftInfo
|
||||
func (m *MetricsAgentInfo) UnmarshalBinary(b []byte) error {
|
||||
var res MetricsAgentInfo
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
61
pkg/models/metrics_bouncer_info.go
Normal file
61
pkg/models/metrics_bouncer_info.go
Normal file
|
@ -0,0 +1,61 @@
|
|||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
package models
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// MetricsBouncerInfo MetricsBouncerInfo
|
||||
//
|
||||
// Software version info (so we can warn users about out-of-date software). The software name and the version are "guessed" from the user-agent
|
||||
//
|
||||
// swagger:model MetricsBouncerInfo
|
||||
type MetricsBouncerInfo struct {
|
||||
|
||||
// name of the component
|
||||
CustomName string `json:"custom_name,omitempty"`
|
||||
|
||||
// last bouncer pull date
|
||||
LastPull string `json:"last_pull,omitempty"`
|
||||
|
||||
// bouncer type (firewall, php ...)
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
// software version
|
||||
Version string `json:"version,omitempty"`
|
||||
}
|
||||
|
||||
// Validate validates this metrics bouncer info
|
||||
func (m *MetricsBouncerInfo) Validate(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this metrics bouncer info based on context it is used
|
||||
func (m *MetricsBouncerInfo) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *MetricsBouncerInfo) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *MetricsBouncerInfo) UnmarshalBinary(b []byte) error {
|
||||
var res MetricsBouncerInfo
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
|
@ -216,3 +216,12 @@ func Int32Ptr(i int32) *int32 {
|
|||
func BoolPtr(b bool) *bool {
|
||||
return &b
|
||||
}
|
||||
|
||||
func InSlice(str string, slice []string) bool {
|
||||
for _, item := range slice {
|
||||
if str == item {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ install -m 644 -D config/patterns/* -t %{buildroot}%{_sysconfdir}/crowdsec/patte
|
|||
install -m 644 -D config/config.yaml %{buildroot}%{_sysconfdir}/crowdsec
|
||||
install -m 644 -D config/simulation.yaml %{buildroot}%{_sysconfdir}/crowdsec
|
||||
install -m 644 -D config/profiles.yaml %{buildroot}%{_sysconfdir}/crowdsec
|
||||
install -m 644 -D config/console_config.yaml %{buildroot}%{_sysconfdir}/crowdsec
|
||||
install -m 644 -D %{SOURCE1} %{buildroot}%{_presetdir}
|
||||
|
||||
install -m 551 plugins/notifications/slack/notification-slack %{buildroot}%{_libdir}/%{name}/plugins/
|
||||
|
|
|
@ -31,6 +31,8 @@ CSCLI_BIN="./cmd/crowdsec-cli/cscli"
|
|||
CLIENT_SECRETS="local_api_credentials.yaml"
|
||||
LAPI_SECRETS="online_api_credentials.yaml"
|
||||
|
||||
CONSOLE_FILE="console_config.yaml"
|
||||
|
||||
BIN_INSTALL_PATH="/usr/local/bin"
|
||||
CROWDSEC_BIN_INSTALLED="${BIN_INSTALL_PATH}/crowdsec"
|
||||
|
||||
|
@ -406,6 +408,7 @@ install_crowdsec() {
|
|||
install -v -m 644 -D ./config/acquis.yaml "${CROWDSEC_CONFIG_PATH}" 1> /dev/null || exit
|
||||
install -v -m 644 -D ./config/profiles.yaml "${CROWDSEC_CONFIG_PATH}" 1> /dev/null || exit
|
||||
install -v -m 644 -D ./config/simulation.yaml "${CROWDSEC_CONFIG_PATH}" 1> /dev/null || exit
|
||||
install -v -m 644 -D ./config/"${CONSOLE_FILE}" "${CROWDSEC_CONFIG_PATH}" 1> /dev/null || exit
|
||||
|
||||
mkdir -p ${PID_DIR} || exit
|
||||
PID=${PID_DIR} DATA=${CROWDSEC_DATA_DIR} CFG=${CROWDSEC_CONFIG_PATH} envsubst '$CFG $PID $DATA' < ./config/user.yaml > ${CROWDSEC_CONFIG_PATH}"/user.yaml" || log_fatal "unable to generate user configuration file"
|
||||
|
|
Loading…
Reference in a new issue