...
1 package cmdopts
2
3 import (
4 "context"
5 "errors"
6 "fmt"
7 "net/url"
8
9 "github.com/cybertec-postgresql/pgwatch/v6/internal/log"
10 "github.com/cybertec-postgresql/pgwatch/v6/internal/sources"
11 )
12
13 type SourceCommand struct {
14 owner *Options
15 Ping SourcePingCommand `command:"ping" description:"Try to connect to configured sources, report errors if any and then exit"`
16 Resolve SourceResolveCommand `command:"resolve" description:"Connect to the configured source(s) and return resolved connection strings for the monitoring targets discovered"`
17
18 }
19
20 func NewSourceCommand(owner *Options) *SourceCommand {
21 return &SourceCommand{
22 owner: owner,
23 Ping: SourcePingCommand{owner: owner},
24 Resolve: SourceResolveCommand{owner: owner},
25 }
26 }
27
28 type SourcePingCommand struct {
29 owner *Options
30 }
31
32 func (cmd *SourcePingCommand) Execute(args []string) error {
33 err := cmd.owner.InitSourceReader(context.Background())
34 if err != nil {
35 return err
36 }
37 srcs, err := cmd.owner.SourcesReaderWriter.GetSources()
38 if err != nil {
39 return err
40 }
41 var foundSources sources.Sources
42 if len(args) == 0 {
43 foundSources = srcs
44 } else {
45 for _, name := range args {
46 for _, s := range srcs {
47 if s.Name == name {
48 foundSources = append(foundSources, s)
49 }
50 }
51 }
52 }
53 var e error
54 resolver := sources.NewResolver()
55 for _, s := range foundSources {
56 switch s.Kind {
57 case sources.SourcePatroniDiscovery:
58 _, e = resolver.ResolveDatabasesFromPatroni(s)
59 case sources.SourcePostgresDiscovery:
60 _, e = resolver.ResolveDatabasesFromPostgres(s)
61 default:
62 mdb := sources.NewSourceConn(s)
63
64 ctx := log.WithLogger(context.Background(), log.NewNoopLogger())
65 if e = mdb.Connect(ctx, cmd.owner.Sources); e == nil {
66 e = mdb.Ping(ctx)
67 }
68 }
69 if e != nil {
70 fmt.Printf("FAIL:\t%s (%s)\n", s.Name, e)
71 } else {
72 fmt.Printf("OK:\t%s\n", s.Name)
73 }
74 err = errors.Join(err, e)
75 }
76
77
78
79 cmd.owner.CompleteCommand(map[bool]int32{true: ExitCodeCmdError, false: ExitCodeOK}[err != nil])
80 return nil
81 }
82
83 type SourceResolveCommand struct {
84 owner *Options
85 }
86
87 func (cmd *SourceResolveCommand) Execute(args []string) error {
88 err := cmd.owner.InitSourceReader(context.Background())
89 if err != nil {
90 return err
91 }
92 srcs, err := cmd.owner.SourcesReaderWriter.GetSources()
93 if err != nil {
94 return err
95 }
96 var foundSources sources.Sources
97 if len(args) == 0 {
98 foundSources = srcs
99 } else {
100 for _, name := range args {
101 for _, s := range srcs {
102 if s.Name == name {
103 foundSources = append(foundSources, s)
104 }
105 }
106 }
107 }
108 conns, err := foundSources.ResolveDatabases(nil)
109 if err != nil {
110 return err
111 }
112 var connstr url.URL
113 connstr.Scheme = "postgresql"
114 for _, conn := range conns {
115 s, ok := conn.(*sources.DbConn)
116 if !ok {
117 continue
118 }
119 src := s.GetSource()
120 if src.ConnStr > "" {
121 fmt.Printf("%s=%s\n", src.Name, src.ConnStr)
122 } else {
123 connstr.Host = fmt.Sprintf("%s:%d", s.ConnConfig.ConnConfig.Host, s.ConnConfig.ConnConfig.Port)
124 connstr.User = url.UserPassword(s.ConnConfig.ConnConfig.User, s.ConnConfig.ConnConfig.Password)
125 connstr.Path = s.ConnConfig.ConnConfig.Database
126 fmt.Printf("%s=%s\n", src.Name, connstr.String())
127 }
128 }
129 cmd.owner.CompleteCommand(ExitCodeOK)
130 return nil
131 }
132