diff --git a/backend/agent/kea.go b/backend/agent/kea.go index 4085a98c3..b4effa619 100644 --- a/backend/agent/kea.go +++ b/backend/agent/kea.go @@ -87,7 +87,7 @@ func collectKeaAllowedLogs(response *keactrl.Response) []string { // Go over returned loggers and collect those found in the returned configuration. var paths []string for _, l := range loggers { - for _, o := range l.OutputOptions { + for _, o := range l.GetAllOutputOptions() { if o.Output != "stdout" && o.Output != "stderr" && !strings.HasPrefix(o.Output, "syslog") { paths = append(paths, o.Output) } diff --git a/backend/agent/kea_test.go b/backend/agent/kea_test.go index 60dcf8fba..f820e2b93 100644 --- a/backend/agent/kea_test.go +++ b/backend/agent/kea_test.go @@ -192,6 +192,115 @@ func TestKeaAllowedLogs(t *testing.T) { require.Len(t, paths, 3) } +// Test the function which extracts the list of log files from the Kea +// application by sending the request to the Kea Control Agent and the +// daemons behind it. This test variant uses output-options alias for +// logger configuration. +func TestKeaAllowedLogsOutputOptionsWithDash(t *testing.T) { + httpClient := NewHTTPClient() + gock.InterceptClient(httpClient.client) + + // The first config-get command should go to the Kea Control Agent. + // The logs should be extracted from there and the subsequent config-get + // commands should be sent to the daemons with which the CA is configured + // to communicate. + defer gock.Off() + caResponseJSON := `[{ + "result": 0, + "arguments": { + "Control-agent": { + "control-sockets": { + "dhcp4": { + "socket-name": "/tmp/dhcp4.sock" + }, + "dhcp6": { + "socket-name": "/tmp/dhcp6.sock" + } + }, + "loggers": [ + { + "output-options": [ + { + "output": "/tmp/kea-ctrl-agent.log" + } + ] + } + ] + } + } + }]` + caResponse := make([]map[string]interface{}, 1) + err := json.Unmarshal([]byte(caResponseJSON), &caResponse) + require.NoError(t, err) + gock.New("https://localhost:45634"). + MatchHeader("Content-Type", "application/json"). + JSON(map[string]string{"command": "config-get"}). + Post("/"). + Reply(200). + JSON(caResponse) + + dhcpResponsesJSON := `[ + { + "result": 0, + "arguments": { + "Dhcp4": { + "loggers": [ + { + "output-options": [ + { + "output": "/tmp/kea-dhcp4.log" + } + ] + } + ] + } + } + }, + { + "result": 0, + "arguments": { + "Dhcp6": { + "loggers": [ + { + "output-options": [ + { + "output": "/tmp/kea-dhcp6.log" + } + ] + } + ] + } + } + } + ]` + dhcpResponses := make([]map[string]interface{}, 2) + err = json.Unmarshal([]byte(dhcpResponsesJSON), &dhcpResponses) + require.NoError(t, err) + + // The config-get command sent to the daemons behind CA should return + // configurations of the DHCPv4 and DHCPv6 daemons. + gock.New("https://localhost:45634"). + MatchHeader("Content-Type", "application/json"). + JSON(map[string]interface{}{"command": "config-get", "service": []string{"dhcp4", "dhcp6"}}). + Post("/"). + Reply(200). + JSON(dhcpResponses) + + ka := &KeaApp{ + BaseApp: BaseApp{ + Type: AppTypeKea, + AccessPoints: makeAccessPoint(AccessPointControl, "localhost", "", 45634, true), + }, + HTTPClient: httpClient, + } + paths, err := ka.DetectAllowedLogs() + require.NoError(t, err) + + // We should have three log files recorded from the returned configurations. + // One from CA, one from DHCPv4 and one from DHCPv6. + require.Len(t, paths, 3) +} + // This test verifies that an error is returned when the number of responses // from the Kea daemons is lower than the number of services specified in the // command. diff --git a/backend/appcfg/kea/keaconfig_test.go b/backend/appcfg/kea/keaconfig_test.go index 7bbf4e967..53bb1ee13 100644 --- a/backend/appcfg/kea/keaconfig_test.go +++ b/backend/appcfg/kea/keaconfig_test.go @@ -336,14 +336,14 @@ func TestGetLoggers(t *testing.T) { require.Len(t, loggers, 2) require.Equal(t, "kea-dhcp4", loggers[0].Name) - require.Len(t, loggers[0].OutputOptions, 1) - require.Equal(t, "stdout", loggers[0].OutputOptions[0].Output) + require.Len(t, loggers[0].GetAllOutputOptions(), 1) + require.Equal(t, "stdout", loggers[0].GetAllOutputOptions()[0].Output) require.Equal(t, "WARN", loggers[0].Severity) require.Zero(t, loggers[0].DebugLevel) require.Equal(t, "kea-dhcp4.bad-packets", loggers[1].Name) - require.Len(t, loggers[1].OutputOptions, 1) - require.Equal(t, "/tmp/badpackets.log", loggers[1].OutputOptions[0].Output) + require.Len(t, loggers[1].GetAllOutputOptions(), 1) + require.Equal(t, "/tmp/badpackets.log", loggers[1].GetAllOutputOptions()[0].Output) require.Equal(t, "DEBUG", loggers[1].Severity) require.Equal(t, 99, loggers[1].DebugLevel) } diff --git a/backend/appcfg/kea/logger.go b/backend/appcfg/kea/logger.go index 8cdadc088..dde38e58e 100644 --- a/backend/appcfg/kea/logger.go +++ b/backend/appcfg/kea/logger.go @@ -1,14 +1,23 @@ package keaconfig // A structure representing a single logger configuration. +// Kea 2.5 introduced an alias output-options. Stork must now +// support both output_options and output-options and return +// combined loggers configuration. type Logger struct { - Name string `json:"name"` - OutputOptions []LoggerOutputOptions `json:"output_options"` - Severity string `json:"severity"` - DebugLevel int `json:"debuglevel"` + Name string `json:"name"` + OutputOptions []LoggerOutputOptions `json:"output_options"` + OutputOptionsAlias []LoggerOutputOptions `json:"output-options"` + Severity string `json:"severity"` + DebugLevel int `json:"debuglevel"` } // A structure representing output_options for a logger. type LoggerOutputOptions struct { Output string `json:"output"` } + +// Returns combined OutputOptions and OutputOptionsAlias. +func (logger Logger) GetAllOutputOptions() []LoggerOutputOptions { + return append(logger.OutputOptions, logger.OutputOptionsAlias...) +} diff --git a/backend/server/database/model/keaconfig.go b/backend/server/database/model/keaconfig.go index 2675abc10..f454a7aa4 100644 --- a/backend/server/database/model/keaconfig.go +++ b/backend/server/database/model/keaconfig.go @@ -340,7 +340,7 @@ func NewHostFromKeaConfigReservation(reservation keaconfig.Reservation, daemon * // can comprise multiple output options. Therefore, this function may return multiple // targets, each corresponding to a single output option. func NewLogTargetsFromKea(logger keaconfig.Logger) (targets []*LogTarget) { - for _, opt := range logger.OutputOptions { + for _, opt := range logger.GetAllOutputOptions() { target := &LogTarget{ Name: logger.Name, Severity: strings.ToLower(logger.Severity),