Skip to content

Commit bf208c2

Browse files
authored
Finish examples (#15)
* Fixes to DB * Add WithTeamDirectory() option to client/servers * Fix version printing and add method to team.Client interface. * Move transports to example directory * Print daemon listening status * Fix log level not printed in status * Add some stuff to README * Add more to README * README * Add code examples to readme * README * README Examples * README * Differences with Hashicorp plugins * Add README to example * README * README * Update ncruces/sqlite dependencies * Use go1.21 in actions * Fix cgo build * Try to fix actions CodeQL * Tidy comments * Tidy comments * Cleanup and comments tidying * Fix actions * Remove logging of cleartext credentials * Fix imports * Fix client imports * Fix and restructure imports * Fix windows action * Finish server examples code * Fix imports and update survey version * Fix imports AGAIN
1 parent 208a5ef commit bf208c2

File tree

10 files changed

+180
-44
lines changed

10 files changed

+180
-44
lines changed

client/client.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,10 @@ import (
2424
"runtime"
2525
"sync"
2626

27-
"github.com/sirupsen/logrus"
28-
2927
"github.com/reeflective/team"
3028
"github.com/reeflective/team/internal/assets"
3129
"github.com/reeflective/team/internal/version"
30+
"github.com/sirupsen/logrus"
3231
)
3332

3433
// Client is the core driver of an application teamclient.

client/config.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ import (
2929
"path/filepath"
3030
"sort"
3131

32-
"gopkg.in/AlecAivazis/survey.v1"
33-
32+
"github.com/AlecAivazis/survey/v2"
3433
"github.com/reeflective/team/internal/assets"
3534
"github.com/reeflective/team/internal/certs"
3635
"github.com/reeflective/team/internal/command"

client/log.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,8 @@ import (
2323
"io"
2424
"path/filepath"
2525

26-
"github.com/sirupsen/logrus"
27-
2826
"github.com/reeflective/team/internal/log"
27+
"github.com/sirupsen/logrus"
2928
)
3029

3130
// NamedLogger returns a new logging "thread" with two fields (optional)

client/options.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,8 @@ import (
2424
"os"
2525
"strings"
2626

27-
"github.com/sirupsen/logrus"
28-
2927
"github.com/reeflective/team/internal/assets"
28+
"github.com/sirupsen/logrus"
3029
)
3130

3231
const noTeamdir = "no team subdirectory"
@@ -113,6 +112,9 @@ func WithInMemory() Options {
113112

114113
// WithConfig sets the client to use a given remote teamserver configuration which
115114
// to connect to, instead of using default on-disk user/application configurations.
115+
// This function will be very useful to library users who wish to implement specific
116+
// remote teamserver selection & connection strategies, depending on the domains and
117+
// and use cases of these tools.
116118
func WithConfig(config *Config) Options {
117119
return func(opts *opts) {
118120
opts.config = config

example/teamclient/main.go

-2
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,3 @@ func main() {
5151
log.Fatal(err)
5252
}
5353
}
54-
55-
func mainPreCommands() {}

example/teamserver/main.go

+142-18
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,31 @@ import (
1111
"github.com/reeflective/team/server/commands"
1212
)
1313

14+
// mainSmallest is the smallest example of a teamserver usage.
15+
// The latter can only serve itself in-memory, since there are no
16+
// remote teamserver listener stacks registered with it. Still, the
17+
// teamserver functionality is complete and works identically regardless.
18+
func mainSmallest() {
19+
teamserver, err := server.New("smallserver")
20+
if err != nil {
21+
log.Fatal(err)
22+
}
23+
24+
// Generate a tree of server-side commands: this tree also has client-only
25+
// commands as a subcommand "client" of the "teamserver" command root here.
26+
serverCmds := commands.Generate(teamserver, teamserver.Self())
27+
serverCmds.Use = "smallserver"
28+
29+
// Generate completions for the tree.
30+
carapace.Gen(serverCmds)
31+
32+
// Run our teamserver binary.
33+
err = serverCmds.Execute()
34+
if err != nil {
35+
log.Fatal(err)
36+
}
37+
}
38+
1439
// main shows how to use a teamserver and teamclient with gRPC backends (transport & RPC).
1540
func main() {
1641
// 1) Teamserver & listeners
@@ -77,6 +102,7 @@ func main() {
77102
}
78103
}
79104

105+
// mainSmallGRPC is the equivalent of main, without comments.
80106
func mainSmallGRPC() {
81107
// Server
82108
gTeamserver := grpc.NewListener()
@@ -103,41 +129,139 @@ func mainSmallGRPC() {
103129
}
104130
}
105131

106-
func mainSmallest() {
107-
teamserver, err := server.New("smallserver")
132+
// mainNoCommands illustrates the fact (without much proof and code) that the teamclient
133+
// and teamserver toolsets are not restrained to CLI usage nor have any obligation to use
134+
// and expose themselves via a CLI.
135+
// On the other hand, some programs may wish to offer it in specific circumstances, or even
136+
// make use of it on the teamclient-side but not on the teamserver. Many setups are possible.
137+
func mainNoCommands() {
138+
// Server
139+
gTeamserver := grpc.NewListener()
140+
141+
teamserver, err := server.New("teamserver", server.WithListener(gTeamserver))
108142
if err != nil {
109143
log.Fatal(err)
110144
}
111145

112-
// Generate a tree of server-side commands: this tree also has client-only
113-
// commands as a subcommand "client" of the "teamserver" command root here.
114-
serverCmds := commands.Generate(teamserver, teamserver.Self())
115-
serverCmds.Use = "smallserver"
146+
// Note that we don't create a self-client for the teamserver: we don't need to have
147+
// any teamclient interaction with the teamserver, and we just want to start/stop it
148+
// from our code.
149+
//
150+
// Instead, let's first start a listener job on some address: this call is non blocking,
151+
// and should we want to keep control of the listener job, we can use the returned ID.
152+
listenerID, err := teamserver.ServeAddr("grpc/mTLS", "localhost", 31350)
153+
if err != nil {
154+
log.Fatal(err)
155+
}
116156

117-
// Generate completions for the tree.
118-
carapace.Gen(serverCmds)
157+
// We can kill the listener from code like this.
158+
err = teamserver.ListenerClose(listenerID)
159+
if err != nil {
160+
log.Fatal(err)
161+
}
119162

120-
// Run our teamserver binary.
121-
err = serverCmds.Execute()
163+
// Finally, simply ask the server to start the daemon (blocking), which also starts
164+
// all listeners that might be saved as persistent jobs. To be noted, you will typically
165+
// favor the above ServeAddr() function in your code rather than the daemon one below,
166+
// since -while being entirely possible- the latter will likely be favored by CLI users.
167+
//
168+
// Note that we don't pass the name of the listener stack we want to use: the daemon
169+
// function always uses the first listener backend that has been registered to the server.
170+
err = teamserver.ServeDaemon("localhost", 31350)
122171
if err != nil {
123172
log.Fatal(err)
124173
}
125174
}
126175

176+
// mainIntegrated demonstrates a use case where the library user might already have an existing,
177+
// established and/or working program. This program will naturally already dispose of core things
178+
// like loggers, database configurations or backends, specific directories for output, etc.
179+
//
180+
// This example therefore shows how to use some other options to tightly integrate the teamserver
181+
// toolset to such programs, while maintaining a strictly identical behavior and function set.
182+
//
183+
// Note that we use nil pointers everywhere in those functions, so this function is very much
184+
// unsafe to run as is. It should be noted again, however, that the library tries to fail safe
185+
// and as early as possible, as illustrated by the various errors returned in examples above.
186+
func mainIntegrated() {
187+
// Use the classic gRPC example backend.
188+
gTeamserver := grpc.NewListener()
189+
190+
var serverOpts []server.Options
191+
serverOpts = append(serverOpts,
192+
// Filesystem
193+
server.WithHomeDirectory("~/.config"), // If we use an appdirectory different from ~/.app/directory .
194+
server.WithTeamDirectory(""), // We might want the teamserver-specific output not to use a specific subdir in it.
195+
196+
// Logging.
197+
server.WithLogger(nil), // We might have a fully set-up logger, with multiple output destinations.
198+
server.WithLogFile("path/to/log.file"), // Or we are fine with default teamserver logger, but a specific file.
199+
200+
// Network (listeners and settings).
201+
server.WithDefaultPort(31340), // Default port of daemon/listeners.
202+
server.WithListener(gTeamserver), // Please see above examples, and the documentation. Any number of them can be registered.
203+
server.WithListener(nil), // Another listener/RPC backend stack used/needed by your application.
204+
205+
// Database (stores users certificates)
206+
server.WithDatabase(nil), // Either pass the teamserver a running DB to store/fetch users certificates data.
207+
server.WithDatabaseConfig(nil), // Or a specific configuration to use for connecting to one.
208+
)
209+
210+
// Pass those options at creation time: some of them cannot be passed later,
211+
// while others can (eg, listener backends can be added and listener configs
212+
// chosen at any time).
213+
teamserver, err := server.New("teamserver", serverOpts...)
214+
if err != nil {
215+
log.Fatal(err)
216+
}
217+
218+
// Again, note that we don't pass the name of the listener stack we want to use: the daemon
219+
// function always uses the first listener backend that has been registered to the server.
220+
err = teamserver.ServeDaemon("localhost", 31350)
221+
if err != nil {
222+
log.Fatal(err)
223+
}
224+
}
225+
226+
// mainInMemory adapts the mainSmallest example with options to instruct the teamserver
227+
// to never touch the host filesystem: all filesystem calls are redirected to an in-memory
228+
// filesystem (which therefore holds all log files and contents in memory), and an in-memory
229+
// SQLite database instance.
127230
func mainInMemory() {
231+
var serverOpts []server.Options
232+
serverOpts = append(serverOpts,
233+
server.WithInMemory(),
234+
server.WithDefaultPort(31340), // Default port of daemon/listeners.
235+
)
236+
237+
// Pass those options at creation time: some of them cannot be passed later,
238+
// while others can (eg, listener backends can be added and listener configs
239+
// chosen at any time).
240+
teamserver, err := server.New("teamserver", serverOpts...)
241+
if err != nil {
242+
log.Fatal(err)
243+
}
244+
245+
// Pass specific options for the teamserver
246+
// self-client, to provide identical behavior.
128247
var clientOpts []client.Options
129248
clientOpts = append(clientOpts,
130249
client.WithInMemory(),
131250
)
132251

133-
var serverOpts []client.Options
134-
serverOpts = append(serverOpts,
135-
client.WithInMemory(),
136-
)
137-
}
252+
// Ask the teamserver to create its own teamclient (without any RPC client backend).
253+
teamclient := teamserver.Self(clientOpts...)
138254

139-
func mainIntegrated() {}
255+
// Generate a tree of server-side commands: this tree also has client-only
256+
// commands as a subcommand "client" of the "teamserver" command root here.
257+
serverCmds := commands.Generate(teamserver, teamclient)
140258

141-
func mainCustom() {}
259+
// Generate completions for the tree.
260+
carapace.Gen(serverCmds)
142261

143-
func mainNoCommands() {}
262+
// Run our teamserver binary.
263+
err = serverCmds.Execute()
264+
if err != nil {
265+
log.Fatal(err)
266+
}
267+
}

go.mod

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ module github.com/reeflective/team
33
go 1.21
44

55
require (
6+
github.com/AlecAivazis/survey/v2 v2.3.7
67
github.com/gofrs/uuid v4.4.0+incompatible
78
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
89
github.com/jedib0t/go-pretty/v6 v6.4.6
9-
github.com/mattn/go-sqlite3 v1.14.17
1010
github.com/ncruces/go-sqlite3 v0.8.4
1111
github.com/ncruces/go-sqlite3/gormlite v0.8.4
1212
github.com/psanford/memfs v0.0.0-20230130182539-4dbf7e3e865e
@@ -16,7 +16,6 @@ require (
1616
github.com/spf13/pflag v1.0.5
1717
google.golang.org/grpc v1.56.1
1818
google.golang.org/protobuf v1.31.0
19-
gopkg.in/AlecAivazis/survey.v1 v1.8.8
2019
gorm.io/driver/mysql v1.5.1
2120
gorm.io/driver/postgres v1.5.2
2221
gorm.io/driver/sqlite v1.5.2
@@ -39,6 +38,7 @@ require (
3938
github.com/mattn/go-colorable v0.1.8 // indirect
4039
github.com/mattn/go-isatty v0.0.17 // indirect
4140
github.com/mattn/go-runewidth v0.0.13 // indirect
41+
github.com/mattn/go-sqlite3 v1.14.17 // indirect
4242
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
4343
github.com/ncruces/julianday v0.1.5 // indirect
4444
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
@@ -50,6 +50,7 @@ require (
5050
golang.org/x/mod v0.11.0 // indirect
5151
golang.org/x/net v0.9.0 // indirect
5252
golang.org/x/sys v0.11.0 // indirect
53+
golang.org/x/term v0.7.0 // indirect
5354
golang.org/x/text v0.12.0 // indirect
5455
golang.org/x/tools v0.6.0 // indirect
5556
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect

0 commit comments

Comments
 (0)