Skip to content

Commit a60f908

Browse files
author
aquatiko
committed
Add support for db-audit logging
1 parent 7182b7a commit a60f908

File tree

12 files changed

+522
-7
lines changed

12 files changed

+522
-7
lines changed

cmd/backup_shedule_test.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,13 +110,9 @@ var _ = Describe("BackupSchedules", func() {
110110
Expect(err).NotTo(HaveOccurred())
111111
session.Wait(2)
112112
o := string(session.Out.Contents()[:])
113-
114-
fmt.Println(o)
115113
expected := `Time Interval(days) Days of the Week Backup Start Time Retention Period(days) State
116114
NA Su,We,Fr ` + getLocalTime("2 3 * * *") + ` 8 ACTIVE` + "\n"
117115
Expect(o).Should(Equal(expected))
118-
fmt.Println(expected)
119-
120116
session.Kill()
121117
})
122118
It("should return list of backup schedules with a paused schedule with incremental backups", func() {
@@ -151,8 +147,6 @@ NA Su,We,Fr ` + getLocalTime("2 3 * * *") + `
151147
Expect(err).NotTo(HaveOccurred())
152148
session.Wait(2)
153149
o := string(session.Out.Contents()[:])
154-
155-
fmt.Println(o)
156150
expected := `Time Interval(days) Incr. Interval(mins) Days of the Week Backup Start Time Retention Period(days) State
157151
NA NA Su,We,Fr ` + getLocalTime("2 3 * * *") + ` 8 ACTIVE` + "\n"
158152
Expect(o).Should(Equal(expected))
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
// Licensed to Yugabyte, Inc. under one or more contributor license
2+
// agreements. See the NOTICE file distributed with this work for
3+
// additional information regarding copyright ownership. Yugabyte
4+
// licenses this file to you under the Apache License, Version 2.0
5+
// (the "License"); you may not use this file except in compliance
6+
// with the License. You may obtain a copy of the License at
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing,
10+
// software distributed under the License is distributed on an
11+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
12+
// KIND, either express or implied. See the License for the
13+
// specific language governing permissions and limitations
14+
// under the License.
15+
16+
package db_audit_logs_exporter
17+
18+
import (
19+
"fmt"
20+
"os"
21+
"strconv"
22+
"strings"
23+
24+
"github.com/sirupsen/logrus"
25+
"github.com/spf13/cobra"
26+
"github.com/spf13/viper"
27+
ybmAuthClient "github.com/yugabyte/ybm-cli/internal/client"
28+
"github.com/yugabyte/ybm-cli/internal/formatter"
29+
openapi "github.com/yugabyte/yugabytedb-managed-go-client-internal"
30+
ybmclient "github.com/yugabyte/yugabytedb-managed-go-client-internal"
31+
)
32+
33+
var DbAuditLogsExporterCmd = &cobra.Command{
34+
Use: "db-audit-logs-exporter",
35+
Short: "Manage DB Audit Logs",
36+
Long: "Manage DB Audit Logs",
37+
Run: func(cmd *cobra.Command, args []string) {
38+
cmd.Help()
39+
},
40+
}
41+
42+
var assignDbAuditLogsExporterCmd = &cobra.Command{
43+
Use: "assign",
44+
Short: "Assign DB Audit",
45+
Long: "Assign DB Audit Logs to a Cluster",
46+
Run: func(cmd *cobra.Command, args []string) {
47+
48+
clusterId, _ := cmd.Flags().GetString("cluster-id")
49+
telemetryProviderId, _ := cmd.Flags().GetString("telemetry-provider-id")
50+
ysqlConfig, _ := cmd.Flags().GetStringToString("ysql-config")
51+
statement_classes, _ := cmd.Flags().GetString("statement_classes")
52+
53+
dbAuditLogsExporterSpec, err := setDbAuditLogsExporterSpec(ysqlConfig, statement_classes, telemetryProviderId)
54+
55+
if err != nil {
56+
logrus.Fatalf(err.Error())
57+
}
58+
59+
authApi, err := ybmAuthClient.NewAuthApiClient()
60+
if err != nil {
61+
logrus.Fatalf(ybmAuthClient.GetApiErrorDetails(err))
62+
}
63+
authApi.GetInfo("", "")
64+
65+
resp, r, err := authApi.AssignDbAuditLogsExporterConfig(clusterId).DbAuditExporterConfigSpec(*dbAuditLogsExporterSpec).Execute()
66+
67+
if err != nil {
68+
logrus.Debugf("Full HTTP response: %v", r)
69+
logrus.Fatalf(ybmAuthClient.GetApiErrorDetails(err))
70+
}
71+
72+
dbAuditTelemetryProviderId := resp.GetData().Info.Id
73+
74+
msg := fmt.Sprintf("The db audit exporter config %s is being created", formatter.Colorize(dbAuditTelemetryProviderId, formatter.GREEN_COLOR))
75+
76+
fmt.Println(msg)
77+
78+
dbAuditLogsExporterCtx := formatter.Context{
79+
Output: os.Stdout,
80+
Format: formatter.NewDbAuditLogsExporterFormat(viper.GetString("output")),
81+
}
82+
83+
formatter.DbAuditLogsExporterWrite(dbAuditLogsExporterCtx, []openapi.DbAuditExporterConfigurationData{resp.GetData()})
84+
},
85+
}
86+
87+
var listDbAuditLogsExporterCmd = &cobra.Command{
88+
Use: "list",
89+
Short: "List DB Audit Logs Export Config",
90+
Long: "List DB Audit Logs Export Config",
91+
Run: func(cmd *cobra.Command, args []string) {
92+
authApi, err := ybmAuthClient.NewAuthApiClient()
93+
if err != nil {
94+
logrus.Fatalf(ybmAuthClient.GetApiErrorDetails(err))
95+
}
96+
authApi.GetInfo("", "")
97+
98+
clusterId, _ := cmd.Flags().GetString("cluster-id")
99+
100+
resp, r, err := authApi.ListDbAuditLogsExportConfigs(clusterId).Execute()
101+
102+
if err != nil {
103+
logrus.Debugf("Full HTTP response: %v", r)
104+
logrus.Fatalf(ybmAuthClient.GetApiErrorDetails(err))
105+
}
106+
107+
dbAuditLogsExporterCtx := formatter.Context{
108+
Output: os.Stdout,
109+
Format: formatter.NewDbAuditLogsExporterFormat(viper.GetString("output")),
110+
}
111+
112+
if len(resp.GetData()) < 1 {
113+
fmt.Println("No DB Audit Logs Exporter found")
114+
return
115+
}
116+
117+
formatter.DbAuditLogsExporterWrite(dbAuditLogsExporterCtx, resp.GetData())
118+
},
119+
}
120+
121+
func init() {
122+
DbAuditLogsExporterCmd.AddCommand(assignDbAuditLogsExporterCmd)
123+
assignDbAuditLogsExporterCmd.Flags().SortFlags = false
124+
assignDbAuditLogsExporterCmd.Flags().String("telemetry-provider-id", "", "[REQUIRED] The ID of the telemetry provider")
125+
assignDbAuditLogsExporterCmd.MarkFlagRequired("telemetry-provider-id")
126+
assignDbAuditLogsExporterCmd.Flags().StringToString("ysql-config", nil, `[REQUIRED] The ysql config to setup DB auditting
127+
Please provide key value pairs as follows:
128+
log_catalog=<boolean>,log_level=<LOG_LEVEL>`)
129+
assignDbAuditLogsExporterCmd.MarkFlagRequired("ysql-config")
130+
assignDbAuditLogsExporterCmd.Flags().String("statement_classes", "", `[REQUIRED] The ysql config statement classes
131+
Please provide key value pairs as follows:
132+
statement_classes=READ,WRITE,MISC`)
133+
assignDbAuditLogsExporterCmd.MarkFlagRequired("statement_classes")
134+
assignDbAuditLogsExporterCmd.Flags().String("cluster-id", "", "[REQUIRED] The cluster ID to assign DB auditting")
135+
assignDbAuditLogsExporterCmd.MarkFlagRequired("cluster-id")
136+
137+
DbAuditLogsExporterCmd.AddCommand(listDbAuditLogsExporterCmd)
138+
listDbAuditLogsExporterCmd.Flags().SortFlags = false
139+
listDbAuditLogsExporterCmd.Flags().String("cluster-id", "", "[REQUIRED] The cluster ID to list DB audit export config")
140+
listDbAuditLogsExporterCmd.MarkFlagRequired("cluster-id")
141+
}
142+
143+
func setDbAuditLogsExporterSpec(ysqlConfigMap map[string]string, statementClasses string, telemetryProviderId string) (*ybmclient.DbAuditExporterConfigSpec, error) {
144+
log_catalog := ysqlConfigMap["log_catalog"]
145+
log_client := ysqlConfigMap["log_client"]
146+
log_level := ysqlConfigMap["log_level"]
147+
log_parameter := ysqlConfigMap["log_parameter"]
148+
log_relation := ysqlConfigMap["log_relation"]
149+
log_statement_once := ysqlConfigMap["log_statement_once"]
150+
151+
var statement_classes_enum []ybmclient.DbAuditYsqlStatmentClassesEnum
152+
153+
if statementClasses != "" {
154+
for _, statement := range strings.Split(statementClasses, ",") {
155+
enumVal, err := ybmclient.NewDbAuditYsqlStatmentClassesEnumFromValue(statement)
156+
if err != nil {
157+
return nil, err
158+
}
159+
statement_classes_enum = append(statement_classes_enum, *enumVal)
160+
}
161+
}
162+
163+
log_settings := ybmclient.NewDbAuditYsqlLogSettingsWithDefaults()
164+
165+
if log_catalog != "" {
166+
catalog, err := strconv.ParseBool(log_catalog)
167+
if err != nil {
168+
return nil, err
169+
}
170+
log_settings.SetLogCatalog(catalog)
171+
}
172+
173+
if log_client != "" {
174+
client, err := strconv.ParseBool(log_client)
175+
if err != nil {
176+
return nil, err
177+
}
178+
log_settings.SetLogClient(client)
179+
}
180+
181+
if log_level != "" {
182+
level, err := ybmclient.NewDbAuditLogLevelEnumFromValue(log_level)
183+
if err != nil {
184+
return nil, err
185+
}
186+
log_settings.SetLogLevel(*level)
187+
}
188+
189+
if log_parameter != "" {
190+
parameter, err := strconv.ParseBool(log_parameter)
191+
if err != nil {
192+
return nil, err
193+
}
194+
log_settings.SetLogParameter(parameter)
195+
}
196+
197+
if log_relation != "" {
198+
relation, err := strconv.ParseBool(log_relation)
199+
if err != nil {
200+
return nil, err
201+
}
202+
log_settings.SetLogRelation(relation)
203+
}
204+
205+
if log_statement_once != "" {
206+
statement_once, err := strconv.ParseBool(log_statement_once)
207+
if err != nil {
208+
return nil, err
209+
}
210+
log_settings.SetLogStatementOnce(statement_once)
211+
}
212+
213+
ysqlConfig := ybmclient.NewDbAuditYsqlExportConfigWithDefaults()
214+
if len(statement_classes_enum) > 0 {
215+
ysqlConfig.SetStatementClasses(statement_classes_enum)
216+
}
217+
218+
ysqlConfig.SetLogSettings(*log_settings)
219+
220+
return ybmclient.NewDbAuditExporterConfigSpec(*ysqlConfig, telemetryProviderId), nil
221+
}

cmd/db_audit_logs_exporter_test.go

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
// Licensed to Yugabyte, Inc. under one or more contributor license
2+
// agreements. See the NOTICE file distributed with this work for
3+
// additional information regarding copyright ownership. Yugabyte
4+
// licenses this file to you under the Apache License, Version 2.0
5+
// (the "License"); you may not use this file except in compliance
6+
// with the License. You may obtain a copy of the License at
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing,
10+
// software distributed under the License is distributed on an
11+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
12+
// KIND, either express or implied. See the License for the
13+
// specific language governing permissions and limitations
14+
// under the License.
15+
16+
package cmd_test
17+
18+
import (
19+
"fmt"
20+
"net/http"
21+
"os"
22+
"os/exec"
23+
24+
. "github.com/onsi/ginkgo/v2"
25+
. "github.com/onsi/gomega"
26+
"github.com/onsi/gomega/gbytes"
27+
"github.com/onsi/gomega/gexec"
28+
"github.com/onsi/gomega/ghttp"
29+
openapi "github.com/yugabyte/yugabytedb-managed-go-client-internal"
30+
)
31+
32+
var _ = Describe("Db Audit", func() {
33+
34+
var (
35+
server *ghttp.Server
36+
statusCode int
37+
args []string
38+
responseAccount openapi.AccountListResponse
39+
responseProject openapi.AccountListResponse
40+
responseDbAudit openapi.DbAuditExporterConfigResponse
41+
responseDbAuditList openapi.DbAuditExporterConfigListResponse
42+
)
43+
44+
BeforeEach(func() {
45+
args = os.Args
46+
os.Args = []string{}
47+
var err error
48+
server, err = newGhttpServer(responseAccount, responseProject)
49+
Expect(err).ToNot(HaveOccurred())
50+
os.Setenv("YBM_HOST", fmt.Sprintf("http://%s", server.Addr()))
51+
os.Setenv("YBM_APIKEY", "test-token")
52+
})
53+
54+
Context("When associating DB Audit config", func() {
55+
It("should associate cluster with DB Audit", func() {
56+
statusCode = 200
57+
err := loadJson("./test/fixtures/db-audit-data.json", &responseDbAudit)
58+
Expect(err).ToNot(HaveOccurred())
59+
server.AppendHandlers(
60+
ghttp.CombineHandlers(
61+
ghttp.VerifyRequest(http.MethodPost, "/api/public/v1/accounts/340af43a-8a7c-4659-9258-4876fd6a207b/projects/78d4459c-0f45-47a5-899a-45ddf43eba6e/clusters/7bb68af6-0875-42e0-8665-dcf634ed9fd1/db-audit-log-exporter-configs"),
62+
ghttp.RespondWithJSONEncodedPtr(&statusCode, responseDbAudit),
63+
),
64+
)
65+
cmd := exec.Command(compiledCLIPath, "db-audit-logs-exporter", "assign", "--cluster-id", "7bb68af6-0875-42e0-8665-dcf634ed9fd1", "--telemetry-provider-id", "7c07c103-e3b2-48b6-ac30-764e9b5275e1", "--ysql-config", "log_catalog=true,log_client=false,log_level=INFO,log_parameter=true", "--statement_classes", "READ,WRITE")
66+
session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter)
67+
Expect(err).NotTo(HaveOccurred())
68+
session.Wait(2)
69+
Expect(session.Out).Should(gbytes.Say(`The db audit exporter config 9e3fabbc-849c-4a77-bdb2-9422e712e7dc is being created
70+
ID Date Created Cluster ID Telemetry Provider ID State Ysql Config
71+
9e3fabbc-849c-4a77-bdb2-9422e712e7dc 2024-02-27T06:30:51.304Z 7bb68af6-0875-42e0-8665-dcf634ed9fd1 7c07c103-e3b2-48b6-ac30-764e9b5275e1 ACTIVE {\"log_settings\":{\"log_catalog\":true,\"log_client\":true,\"log_level\":\"LOG\",\"log_parameter\":false,\"log_relation\":false,\"log_statement_once\":false},\"statement_classes\":\[\"READ\",\"WRITE\"]}`))
72+
session.Kill()
73+
})
74+
It("should return required field name and type when not set", func() {
75+
76+
cmd := exec.Command(compiledCLIPath, "db-audit-logs-exporter", "assign")
77+
session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter)
78+
Expect(err).NotTo(HaveOccurred())
79+
session.Wait(2)
80+
Expect(session.Err).Should(gbytes.Say(`\bError: required flag\(s\) "telemetry-provider-id", "ysql-config", "statement_classes", "cluster-id" not set\b`))
81+
session.Kill()
82+
})
83+
})
84+
85+
Context("When listing db audit exporter config", func() {
86+
It("should return the list of config", func() {
87+
statusCode = 200
88+
err := loadJson("./test/fixtures/list-db-audit.json", &responseDbAuditList)
89+
Expect(err).ToNot(HaveOccurred())
90+
server.AppendHandlers(
91+
ghttp.CombineHandlers(
92+
ghttp.VerifyRequest(http.MethodGet, "/api/public/v1/accounts/340af43a-8a7c-4659-9258-4876fd6a207b/projects/78d4459c-0f45-47a5-899a-45ddf43eba6e/clusters/7bb68af6-0875-42e0-8665-dcf634ed9fd1/db-audit-log-exporter-configs"),
93+
ghttp.RespondWithJSONEncodedPtr(&statusCode, responseDbAuditList),
94+
),
95+
)
96+
cmd := exec.Command(compiledCLIPath, "db-audit-logs-exporter", "list", "--cluster-id", "7bb68af6-0875-42e0-8665-dcf634ed9fd1")
97+
session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter)
98+
Expect(err).NotTo(HaveOccurred())
99+
session.Wait(2)
100+
Expect(session.Out).Should(gbytes.Say(`ID Date Created Cluster ID Telemetry Provider ID State Ysql Config
101+
9e3fabbc-849c-4a77-bdb2-9422e712e7dc 2024-02-27T06:30:51.304Z 7bb68af6-0875-42e0-8665-dcf634ed9fd1 7c07c103-e3b2-48b6-ac30-764e9b5275e1 ACTIVE {\"log_settings\":{\"log_catalog\":true,\"log_client\":true,\"log_level\":\"LOG\",\"log_parameter\":false,\"log_relation\":false,\"log_statement_once\":false},\"statement_classes\":\[\"READ\",\"WRITE\"]}`))
102+
session.Kill()
103+
})
104+
It("should return required field name and type when not set", func() {
105+
106+
cmd := exec.Command(compiledCLIPath, "db-audit-logs-exporter", "list")
107+
session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter)
108+
Expect(err).NotTo(HaveOccurred())
109+
session.Wait(2)
110+
Expect(session.Err).Should(gbytes.Say("(?m:Error: required flag\\(s\\) \"cluster-id\" not set$)"))
111+
session.Kill()
112+
})
113+
114+
})
115+
116+
AfterEach(func() {
117+
os.Args = args
118+
server.Close()
119+
})
120+
121+
})

cmd/root.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"github.com/yugabyte/ybm-cli/cmd/cdc"
3030
"github.com/yugabyte/ybm-cli/cmd/cluster"
3131
"github.com/yugabyte/ybm-cli/cmd/metrics_exporter"
32+
"github.com/yugabyte/ybm-cli/cmd/db_audit_logs_exporter"
3233
"github.com/yugabyte/ybm-cli/cmd/nal"
3334
"github.com/yugabyte/ybm-cli/cmd/permission"
3435
"github.com/yugabyte/ybm-cli/cmd/region"
@@ -135,6 +136,7 @@ func init() {
135136
rootCmd.AddCommand(api_key.ApiKeyCmd)
136137
rootCmd.AddCommand(user.UserCmd)
137138
rootCmd.AddCommand(metrics_exporter.MetricsExporterCmd)
139+
rootCmd.AddCommand(db_audit_logs_exporter.DbAuditLogsExporterCmd)
138140
util.AddCommandIfFeatureFlag(rootCmd, tools.ToolsCmd, util.TOOLS)
139141
util.AddCommandIfFeatureFlag(rootCmd, cdc.CdcCmd, util.CDC)
140142

0 commit comments

Comments
 (0)