-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cobrautil v2 #19
Merged
Merged
cobrautil v2 #19
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
0f091ab
separates functionality by packages
vroldanbet 14eed44
introduces a fluent zerolog cobrautil package
vroldanbet 6eeae43
moves OTel package to v2 design
vroldanbet 8627e24
fix linter errors
vroldanbet 587e82b
also turn flagPrefix into a flag
vroldanbet 553eadd
refactor http package to follow v2 design
vroldanbet d133cf1
refactor gRPC package to follow v2 design
vroldanbet b76e13c
tune logging messages
vroldanbet File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
package grpc | ||
|
||
import ( | ||
"fmt" | ||
"net" | ||
"time" | ||
|
||
"github.com/jzelinskie/cobrautil/v2" | ||
|
||
"github.com/go-logr/logr" | ||
"github.com/jzelinskie/stringz" | ||
"github.com/spf13/cobra" | ||
"github.com/spf13/pflag" | ||
"google.golang.org/grpc" | ||
"google.golang.org/grpc/credentials" | ||
"google.golang.org/grpc/keepalive" | ||
) | ||
|
||
// ConfigureFunc is a function used to configure this CobraUtil | ||
type ConfigureFunc = func(cu *CobraUtil) | ||
|
||
// New creates a configuration that exposes RegisterFlags and RunE | ||
// to integrate with cobra | ||
func New(serviceName string, configurations ...ConfigureFunc) *CobraUtil { | ||
cu := CobraUtil{ | ||
serviceName: stringz.DefaultEmpty(serviceName, "grpc"), | ||
preRunLevel: 0, | ||
logger: logr.Discard(), | ||
defaultAddr: ":50051", | ||
defaultEnabled: false, | ||
flagPrefix: "grpc", | ||
} | ||
for _, configure := range configurations { | ||
configure(&cu) | ||
} | ||
return &cu | ||
} | ||
|
||
// CobraUtil carries the configuration for a otel CobraRunFunc | ||
type CobraUtil struct { | ||
flagPrefix string | ||
serviceName string | ||
defaultAddr string | ||
defaultEnabled bool | ||
logger logr.Logger | ||
preRunLevel int | ||
} | ||
|
||
// RegisterGrpcServerFlags adds the following flags for use with | ||
// GrpcServerFromFlags: | ||
// - "$PREFIX-addr" | ||
// - "$PREFIX-tls-cert-path" | ||
// - "$PREFIX-tls-key-path" | ||
// - "$PREFIX-max-conn-age" | ||
func RegisterGrpcServerFlags(flags *pflag.FlagSet, flagPrefix, serviceName, defaultAddr string, defaultEnabled bool) { | ||
serviceName = stringz.DefaultEmpty(serviceName, "grpc") | ||
defaultAddr = stringz.DefaultEmpty(defaultAddr, ":50051") | ||
prefixed := cobrautil.PrefixJoiner(stringz.DefaultEmpty(flagPrefix, "grpc")) | ||
|
||
flags.String(prefixed("addr"), defaultAddr, "address to listen on to serve "+serviceName) | ||
flags.String(prefixed("network"), "tcp", "network type to serve "+serviceName+` ("tcp", "tcp4", "tcp6", "unix", "unixpacket")`) | ||
flags.String(prefixed("tls-cert-path"), "", "local path to the TLS certificate used to serve "+serviceName) | ||
flags.String(prefixed("tls-key-path"), "", "local path to the TLS key used to serve "+serviceName) | ||
flags.Duration(prefixed("max-conn-age"), 30*time.Second, "how long a connection serving "+serviceName+" should be able to live") | ||
flags.Bool(prefixed("enabled"), defaultEnabled, "enable "+serviceName+" gRPC server") | ||
} | ||
|
||
// RegisterGrpcServerFlags adds the following flags for use with | ||
// GrpcServerFromFlags: | ||
// - "$PREFIX-addr" | ||
// - "$PREFIX-tls-cert-path" | ||
// - "$PREFIX-tls-key-path" | ||
// - "$PREFIX-max-conn-age" | ||
func (cu CobraUtil) RegisterGrpcServerFlags(flags *pflag.FlagSet) { | ||
RegisterGrpcServerFlags(flags, cu.flagPrefix, cu.serviceName, cu.defaultAddr, cu.defaultEnabled) | ||
} | ||
|
||
// ServerFromFlags creates an *grpc.Server as configured by the flags from | ||
// RegisterGrpcServerFlags(). | ||
func ServerFromFlags(cmd *cobra.Command, flagPrefix string, opts ...grpc.ServerOption) (*grpc.Server, error) { | ||
return New("", WithFlagPrefix(flagPrefix)).ServerFromFlags(cmd, opts...) | ||
} | ||
|
||
// ServerFromFlags creates an *grpc.Server as configured by the flags from | ||
// RegisterGrpcServerFlags(). | ||
func (cu CobraUtil) ServerFromFlags(cmd *cobra.Command, opts ...grpc.ServerOption) (*grpc.Server, error) { | ||
prefixed := cobrautil.PrefixJoiner(cu.flagPrefix) | ||
|
||
opts = append(opts, grpc.KeepaliveParams(keepalive.ServerParameters{ | ||
MaxConnectionAge: cobrautil.MustGetDuration(cmd, prefixed("max-conn-age")), | ||
})) | ||
|
||
certPath := cobrautil.MustGetStringExpanded(cmd, prefixed("tls-cert-path")) | ||
keyPath := cobrautil.MustGetStringExpanded(cmd, prefixed("tls-key-path")) | ||
|
||
switch { | ||
case isInsecure(certPath, keyPath): | ||
return grpc.NewServer(opts...), nil | ||
|
||
case isSecure(certPath, keyPath): | ||
creds, err := credentials.NewServerTLSFromFile(certPath, keyPath) | ||
if err != nil { | ||
return nil, err | ||
} | ||
opts = append(opts, grpc.Creds(creds)) | ||
return grpc.NewServer(opts...), nil | ||
|
||
default: | ||
return nil, fmt.Errorf( | ||
"failed to start gRPC server: must provide both --%s-tls-cert-path and --%s-tls-key-path", | ||
cu.flagPrefix, | ||
cu.flagPrefix, | ||
) | ||
} | ||
} | ||
|
||
// ListenFromFlags listens on an gRPC server using the configuration stored | ||
// in the cobra command that was registered with RegisterGrpcServerFlags. | ||
func ListenFromFlags(cmd *cobra.Command, flagPrefix string, srv *grpc.Server, preRunLevel int) error { | ||
return New("", WithPreRunLevel(preRunLevel), WithFlagPrefix(flagPrefix)).ListenFromFlags(cmd, srv) | ||
} | ||
|
||
// ListenFromFlags listens on an gRPC server using the configuration stored | ||
// in the cobra command that was registered with RegisterGrpcServerFlags. | ||
func (cu CobraUtil) ListenFromFlags(cmd *cobra.Command, srv *grpc.Server) error { | ||
prefixed := cobrautil.PrefixJoiner(cu.flagPrefix) | ||
|
||
if !cobrautil.MustGetBool(cmd, prefixed("enabled")) { | ||
return nil | ||
} | ||
|
||
network := cobrautil.MustGetString(cmd, prefixed("network")) | ||
addr := cobrautil.MustGetStringExpanded(cmd, prefixed("addr")) | ||
|
||
l, err := net.Listen(network, addr) | ||
if err != nil { | ||
return fmt.Errorf("failed to listen on addr for gRPC server: %w", err) | ||
} | ||
|
||
certPath := cobrautil.MustGetStringExpanded(cmd, prefixed("tls-cert-path")) | ||
keyPath := cobrautil.MustGetStringExpanded(cmd, prefixed("tls-key-path")) | ||
cu.logger.V(cu.preRunLevel).Info( | ||
"grpc server started listening", | ||
"addr", addr, | ||
"network", network, | ||
"prefix", cu.flagPrefix, | ||
"insecure", isInsecure(certPath, keyPath)) | ||
|
||
if err := srv.Serve(l); err != nil { | ||
return fmt.Errorf("failed to serve gRPC: %w", err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// WithLogger defines the logger used to log messages in this package | ||
func WithLogger(logger logr.Logger) ConfigureFunc { | ||
return func(cu *CobraUtil) { | ||
cu.logger = logger | ||
} | ||
} | ||
|
||
// WithDefaultAddress defines the default value of the address the server will listen at. | ||
// Defaults to ":50051" | ||
func WithDefaultAddress(addr string) ConfigureFunc { | ||
return func(cu *CobraUtil) { | ||
cu.defaultAddr = addr | ||
} | ||
} | ||
|
||
// WithDefaultEnabled defines whether the gRPC server is enabled by default. Defaults to "false". | ||
func WithDefaultEnabled(enabled bool) ConfigureFunc { | ||
return func(cu *CobraUtil) { | ||
cu.defaultEnabled = enabled | ||
} | ||
} | ||
|
||
// WithFlagPrefix defines prefix used with the generated flags. Defaults to "grpc". | ||
func WithFlagPrefix(flagPrefix string) ConfigureFunc { | ||
return func(cu *CobraUtil) { | ||
cu.flagPrefix = flagPrefix | ||
} | ||
} | ||
|
||
// WithPreRunLevel defines the logging level used for pre-run log messages. Defaults to "debug". | ||
func WithPreRunLevel(preRunLevel int) ConfigureFunc { | ||
return func(cu *CobraUtil) { | ||
cu.preRunLevel = preRunLevel | ||
} | ||
} | ||
|
||
func isInsecure(certPath, keyPath string) bool { | ||
return certPath == "" && keyPath == "" | ||
} | ||
|
||
func isSecure(certPath, keyPath string) bool { | ||
return certPath != "" && keyPath != "" | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd name this type config in each package instead of cobrautil. I think it makes sense to also make the type private, since all of the fields are also private. I'm pretty sure you can still return the type from functions, but folks will just be unable to construct it from a literal in other packages.
Picking up optgen might also be a good idea for this too: https://github.com/ecordell/optgen