Skip to content

Commit 89ec2a2

Browse files
committed
add all command for audit log
1 parent 997bde8 commit 89ec2a2

23 files changed

+1347
-125
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package auditlog
2+
3+
import (
4+
"github.com/spf13/cobra"
5+
"github.com/tidbcloud/tidbcloud-cli/internal"
6+
)
7+
8+
func AuditLoggingCmd(h *internal.Helper) *cobra.Command {
9+
var auditLoggingCmd = &cobra.Command{
10+
Use: "audit-log",
11+
Short: "Manage TiDB Cloud Serverless database audit logging",
12+
Aliases: []string{"al"},
13+
}
14+
15+
auditLoggingCmd.AddCommand(DownloadCmd(h))
16+
auditLoggingCmd.AddCommand(DescribeCmd(h))
17+
auditLoggingCmd.AddCommand(ConfigCmd(h))
18+
auditLoggingCmd.AddCommand(EnableCmd(h))
19+
auditLoggingCmd.AddCommand(DisableCmd(h))
20+
21+
return auditLoggingCmd
22+
}
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
package auditlog
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/AlecAivazis/survey/v2"
7+
"github.com/AlecAivazis/survey/v2/terminal"
8+
"github.com/fatih/color"
9+
"github.com/juju/errors"
10+
"github.com/spf13/cobra"
11+
"github.com/tidbcloud/tidbcloud-cli/internal"
12+
"github.com/tidbcloud/tidbcloud-cli/internal/config"
13+
"github.com/tidbcloud/tidbcloud-cli/internal/flag"
14+
"github.com/tidbcloud/tidbcloud-cli/internal/service/cloud"
15+
"github.com/tidbcloud/tidbcloud-cli/internal/util"
16+
"github.com/tidbcloud/tidbcloud-cli/pkg/tidbcloud/v1beta1/serverless/cluster"
17+
)
18+
19+
type ConfigOpts struct {
20+
interactive bool
21+
}
22+
23+
func (c ConfigOpts) NonInteractiveFlags() []string {
24+
return []string{
25+
flag.ClusterID,
26+
flag.AuditLogUnRedacted,
27+
}
28+
}
29+
30+
type mutableField string
31+
32+
const (
33+
Unredacted mutableField = "unredacted"
34+
)
35+
36+
var mutableFields = []string{
37+
string(Unredacted),
38+
}
39+
40+
func (c *ConfigOpts) MarkInteractive(cmd *cobra.Command) error {
41+
flags := c.NonInteractiveFlags()
42+
for _, fn := range flags {
43+
f := cmd.Flags().Lookup(fn)
44+
if f != nil && f.Changed {
45+
c.interactive = false
46+
break
47+
}
48+
}
49+
// Mark required flags
50+
if !c.interactive {
51+
err := cmd.MarkFlagRequired(flag.ClusterID)
52+
if err != nil {
53+
return err
54+
}
55+
cmd.MarkFlagsOneRequired(flag.AuditLogUnRedacted)
56+
}
57+
return nil
58+
}
59+
60+
func ConfigCmd(h *internal.Helper) *cobra.Command {
61+
opts := ConfigOpts{
62+
interactive: true,
63+
}
64+
65+
var configCmd = &cobra.Command{
66+
Use: "config",
67+
Short: "Configure the database audit logging",
68+
Args: cobra.NoArgs,
69+
Annotations: make(map[string]string),
70+
Example: fmt.Sprintf(` Conigure the database audit logging in interactive mode:
71+
$ %[1]s serverless audit-log config
72+
73+
Unredacted the database audit logging in non-interactive mode:
74+
$ %[1]s serverless audit-log config -c <cluster-id> --auditlog.unredacted`, config.CliName),
75+
PreRunE: func(cmd *cobra.Command, args []string) error {
76+
return opts.MarkInteractive(cmd)
77+
},
78+
RunE: func(cmd *cobra.Command, args []string) error {
79+
d, err := h.Client()
80+
if err != nil {
81+
return err
82+
}
83+
ctx := cmd.Context()
84+
85+
var clusterID string
86+
var unredacted bool
87+
if opts.interactive {
88+
if !h.IOStreams.CanPrompt {
89+
return errors.New("The terminal doesn't support interactive mode, please use non-interactive mode")
90+
}
91+
project, err := cloud.GetSelectedProject(ctx, h.QueryPageSize, d)
92+
if err != nil {
93+
return err
94+
}
95+
selectedCluster, err := cloud.GetSelectedCluster(ctx, project.ID, h.QueryPageSize, d)
96+
if err != nil {
97+
return err
98+
}
99+
clusterID = selectedCluster.ID
100+
101+
fieldName, err := cloud.GetSelectedField(mutableFields, "Choose one field to config:")
102+
if err != nil {
103+
return err
104+
}
105+
106+
switch fieldName {
107+
case string(Unredacted):
108+
prompt := &survey.Confirm{
109+
Message: "unredacted the database audit logging of the cluster?",
110+
Default: false,
111+
}
112+
err = survey.AskOne(prompt, &unredacted)
113+
if err != nil {
114+
if err == terminal.InterruptErr {
115+
return util.InterruptError
116+
} else {
117+
return err
118+
}
119+
}
120+
121+
}
122+
} else {
123+
cID, err := cmd.Flags().GetString(flag.ClusterID)
124+
if err != nil {
125+
return errors.Trace(err)
126+
}
127+
clusterID = cID
128+
unredacted, err = cmd.Flags().GetBool(flag.AuditLogUnRedacted)
129+
if err != nil {
130+
return errors.Trace(err)
131+
}
132+
}
133+
134+
println("clusterID:", clusterID, "unredacted:", unredacted)
135+
136+
body := &cluster.V1beta1ServerlessServicePartialUpdateClusterBody{
137+
Cluster: &cluster.RequiredTheClusterToBeUpdated{
138+
AuditLogConfig: &cluster.V1beta1ClusterAuditLogConfig{
139+
Unredacted: *cluster.NewNullableBool(&unredacted),
140+
},
141+
},
142+
UpdateMask: "auditLogConfig",
143+
}
144+
_, err = d.PartialUpdateCluster(ctx, clusterID, body)
145+
if err != nil {
146+
return errors.Trace(err)
147+
}
148+
fmt.Fprintln(h.IOStreams.Out, color.GreenString(fmt.Sprintf("configure cluster %s database audit logging succeed", clusterID)))
149+
return nil
150+
},
151+
}
152+
153+
configCmd.Flags().StringP(flag.ClusterID, flag.ClusterIDShort, "", "The ID of the cluster to be updated.")
154+
configCmd.Flags().Bool(flag.AuditLogUnRedacted, false, "Unredacted the database audit logging.")
155+
return configCmd
156+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package auditlog
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/juju/errors"
7+
"github.com/spf13/cobra"
8+
"github.com/tidbcloud/tidbcloud-cli/internal"
9+
"github.com/tidbcloud/tidbcloud-cli/internal/config"
10+
"github.com/tidbcloud/tidbcloud-cli/internal/flag"
11+
"github.com/tidbcloud/tidbcloud-cli/internal/output"
12+
"github.com/tidbcloud/tidbcloud-cli/internal/service/cloud"
13+
"github.com/tidbcloud/tidbcloud-cli/pkg/tidbcloud/v1beta1/serverless/cluster"
14+
)
15+
16+
type DescribeOpts struct {
17+
interactive bool
18+
}
19+
20+
func (c DescribeOpts) NonInteractiveFlags() []string {
21+
return []string{
22+
flag.ClusterID,
23+
}
24+
}
25+
26+
func (c *DescribeOpts) MarkInteractive(cmd *cobra.Command) error {
27+
flags := c.NonInteractiveFlags()
28+
for _, fn := range flags {
29+
f := cmd.Flags().Lookup(fn)
30+
if f != nil && f.Changed {
31+
c.interactive = false
32+
break
33+
}
34+
}
35+
// Mark required flags
36+
if !c.interactive {
37+
for _, fn := range flags {
38+
err := cmd.MarkFlagRequired(fn)
39+
if err != nil {
40+
return err
41+
}
42+
}
43+
}
44+
return nil
45+
}
46+
47+
func DescribeCmd(h *internal.Helper) *cobra.Command {
48+
opts := DescribeOpts{
49+
interactive: true,
50+
}
51+
52+
var describeCmd = &cobra.Command{
53+
Use: "describe",
54+
Short: "Describe the database audit logging configuration",
55+
Aliases: []string{"get"},
56+
Args: cobra.NoArgs,
57+
Example: fmt.Sprintf(` Get the database audit logging configuration in interactive mode:
58+
$ %[1]s serverless audit-log describe
59+
60+
Get the database audit logging configuration in non-interactive mode:
61+
$ %[1]s serverless audit-log describe -c <cluster-id> `, config.CliName),
62+
PreRunE: func(cmd *cobra.Command, args []string) error {
63+
return opts.MarkInteractive(cmd)
64+
},
65+
RunE: func(cmd *cobra.Command, args []string) error {
66+
d, err := h.Client()
67+
if err != nil {
68+
return err
69+
}
70+
ctx := cmd.Context()
71+
72+
var clusterID string
73+
if opts.interactive {
74+
if !h.IOStreams.CanPrompt {
75+
return errors.New("The terminal doesn't support interactive mode, please use non-interactive mode")
76+
}
77+
project, err := cloud.GetSelectedProject(ctx, h.QueryPageSize, d)
78+
if err != nil {
79+
return err
80+
}
81+
cluster, err := cloud.GetSelectedCluster(ctx, project.ID, h.QueryPageSize, d)
82+
if err != nil {
83+
return err
84+
}
85+
clusterID = cluster.ID
86+
} else {
87+
clusterID, err = cmd.Flags().GetString(flag.ClusterID)
88+
if err != nil {
89+
return errors.Trace(err)
90+
}
91+
}
92+
93+
cluster, err := d.GetCluster(ctx, clusterID, cluster.SERVERLESSSERVICEGETCLUSTERVIEWPARAMETER_BASIC)
94+
if err != nil {
95+
return errors.Trace(err)
96+
}
97+
98+
err = output.PrintJson(h.IOStreams.Out, cluster.AuditLogConfig)
99+
return errors.Trace(err)
100+
},
101+
}
102+
103+
describeCmd.Flags().StringP(flag.ClusterID, flag.ClusterIDShort, "", "The cluster ID.")
104+
return describeCmd
105+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package auditlog
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/fatih/color"
7+
"github.com/juju/errors"
8+
"github.com/spf13/cobra"
9+
"github.com/tidbcloud/tidbcloud-cli/internal"
10+
"github.com/tidbcloud/tidbcloud-cli/internal/config"
11+
"github.com/tidbcloud/tidbcloud-cli/internal/flag"
12+
"github.com/tidbcloud/tidbcloud-cli/internal/service/cloud"
13+
"github.com/tidbcloud/tidbcloud-cli/pkg/tidbcloud/v1beta1/serverless/cluster"
14+
)
15+
16+
type DisableOpts struct {
17+
interactive bool
18+
}
19+
20+
func (c DisableOpts) NonInteractiveFlags() []string {
21+
return []string{
22+
flag.ClusterID,
23+
}
24+
}
25+
26+
func (c *DisableOpts) MarkInteractive(cmd *cobra.Command) error {
27+
flags := c.NonInteractiveFlags()
28+
for _, fn := range flags {
29+
f := cmd.Flags().Lookup(fn)
30+
if f != nil && f.Changed {
31+
c.interactive = false
32+
break
33+
}
34+
}
35+
// Mark required flags
36+
if !c.interactive {
37+
for _, fn := range flags {
38+
err := cmd.MarkFlagRequired(fn)
39+
if err != nil {
40+
return err
41+
}
42+
}
43+
}
44+
return nil
45+
}
46+
47+
func DisableCmd(h *internal.Helper) *cobra.Command {
48+
opts := DisableOpts{
49+
interactive: true,
50+
}
51+
52+
var disableCmd = &cobra.Command{
53+
Use: "disable",
54+
Short: "disable the database audit logging",
55+
Args: cobra.NoArgs,
56+
Example: fmt.Sprintf(` disable the database audit logging in interactive mode:
57+
$ %[1]s serverless audit-log disable
58+
59+
disable the database audit logging in non-interactive mode:
60+
$ %[1]s serverless audit-log disable -c <cluster-id> `, config.CliName),
61+
PreRunE: func(cmd *cobra.Command, args []string) error {
62+
return opts.MarkInteractive(cmd)
63+
},
64+
RunE: func(cmd *cobra.Command, args []string) error {
65+
d, err := h.Client()
66+
if err != nil {
67+
return err
68+
}
69+
ctx := cmd.Context()
70+
71+
var clusterID string
72+
if opts.interactive {
73+
if !h.IOStreams.CanPrompt {
74+
return errors.New("The terminal doesn't support interactive mode, please use non-interactive mode")
75+
}
76+
project, err := cloud.GetSelectedProject(ctx, h.QueryPageSize, d)
77+
if err != nil {
78+
return err
79+
}
80+
cluster, err := cloud.GetSelectedCluster(ctx, project.ID, h.QueryPageSize, d)
81+
if err != nil {
82+
return err
83+
}
84+
clusterID = cluster.ID
85+
} else {
86+
clusterID, err = cmd.Flags().GetString(flag.ClusterID)
87+
if err != nil {
88+
return errors.Trace(err)
89+
}
90+
}
91+
92+
enable := false
93+
body := &cluster.V1beta1ServerlessServicePartialUpdateClusterBody{
94+
Cluster: &cluster.RequiredTheClusterToBeUpdated{
95+
AuditLogConfig: &cluster.V1beta1ClusterAuditLogConfig{
96+
Enabled: *cluster.NewNullableBool(&enable),
97+
},
98+
},
99+
UpdateMask: "auditLogConfig",
100+
}
101+
_, err = d.PartialUpdateCluster(ctx, clusterID, body)
102+
if err != nil {
103+
return errors.Trace(err)
104+
}
105+
fmt.Fprintln(h.IOStreams.Out, color.GreenString(fmt.Sprintf("cluster %s database audit logging disabled", clusterID)))
106+
return nil
107+
},
108+
}
109+
110+
disableCmd.Flags().StringP(flag.ClusterID, flag.ClusterIDShort, "", "The cluster ID.")
111+
return disableCmd
112+
}

0 commit comments

Comments
 (0)