mirror of
https://github.com/k8sgpt-ai/k8sgpt.git
synced 2026-07-17 10:20:41 +00:00
grpc.NewClient returns a nil *ClientConn when it fails (for example on an invalid connection string). Store and Load registered defer conn.Close() before checking the returned error, so a client-creation failure triggered a nil pointer dereference in the deferred Close instead of returning the error. Move defer conn.Close() to after the error check in both methods. Add a regression test that drives Store and Load with an invalid connection string and asserts they return an error without panicking. The deferred conn.Close() now discards its error with a plain _ = conn.Close() rather than logging it: grpc's ClientConn.Close() only returns a non-nil error on a double-close, which can't happen from a single call site here, so a logging branch would be dead code that patch coverage can never satisfy. Signed-off-by: Anas Khan <83116240+anxkhn@users.noreply.github.com>
134 lines
3.4 KiB
Go
134 lines
3.4 KiB
Go
package cache
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
|
|
rpc "buf.build/gen/go/interplex-ai/schemas/grpc/go/protobuf/schema/v1/schemav1grpc"
|
|
schemav1 "buf.build/gen/go/interplex-ai/schemas/protocolbuffers/go/protobuf/schema/v1"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/credentials/insecure"
|
|
)
|
|
|
|
var _ ICache = (*InterplexCache)(nil)
|
|
|
|
type InterplexCache struct {
|
|
configuration InterplexCacheConfiguration
|
|
client InterplexClient
|
|
cacheServiceClient rpc.CacheServiceClient
|
|
noCache bool
|
|
}
|
|
|
|
type InterplexCacheConfiguration struct {
|
|
ConnectionString string `mapstructure:"connectionString" yaml:"connectionString,omitempty"`
|
|
}
|
|
|
|
type InterplexClient struct {
|
|
}
|
|
|
|
func (c *InterplexCache) Configure(cacheInfo CacheProvider) error {
|
|
|
|
if cacheInfo.Interplex.ConnectionString == "" {
|
|
return errors.New("connection string is required")
|
|
}
|
|
c.configuration.ConnectionString = cacheInfo.Interplex.ConnectionString
|
|
return nil
|
|
}
|
|
|
|
func (c *InterplexCache) Store(key string, data string) error {
|
|
|
|
if os.Getenv("INTERPLEX_LOCAL_MODE") != "" {
|
|
c.configuration.ConnectionString = "localhost:8084"
|
|
}
|
|
|
|
conn, err := grpc.NewClient(c.configuration.ConnectionString, grpc.WithInsecure(), grpc.WithBlock())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// Best-effort cleanup: nothing meaningful to do with a close error here.
|
|
defer func() { _ = conn.Close() }()
|
|
serviceClient := rpc.NewCacheServiceClient(conn)
|
|
c.cacheServiceClient = serviceClient
|
|
req := schemav1.SetRequest{
|
|
Key: key,
|
|
Value: data,
|
|
}
|
|
_, err = c.cacheServiceClient.Set(context.Background(), &req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *InterplexCache) Load(key string) (string, error) {
|
|
if os.Getenv("INTERPLEX_LOCAL_MODE") != "" {
|
|
c.configuration.ConnectionString = "localhost:8084"
|
|
}
|
|
|
|
conn, err := grpc.NewClient(c.configuration.ConnectionString, grpc.WithInsecure(), grpc.WithBlock())
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
// Best-effort cleanup: nothing meaningful to do with a close error here.
|
|
defer func() { _ = conn.Close() }()
|
|
serviceClient := rpc.NewCacheServiceClient(conn)
|
|
c.cacheServiceClient = serviceClient
|
|
req := schemav1.GetRequest{
|
|
Key: key,
|
|
}
|
|
resp, err := c.cacheServiceClient.Get(context.Background(), &req)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return resp.Value, nil
|
|
}
|
|
|
|
func (c *InterplexCache) List() ([]CacheObjectDetails, error) {
|
|
// Not implemented for Interplex cache
|
|
return []CacheObjectDetails{}, nil
|
|
}
|
|
|
|
func (c *InterplexCache) Remove(key string) error {
|
|
if os.Getenv("INTERPLEX_LOCAL_MODE") != "" {
|
|
c.configuration.ConnectionString = "localhost:8084"
|
|
}
|
|
|
|
conn, err := grpc.NewClient(c.configuration.ConnectionString, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer func() {
|
|
if err := conn.Close(); err != nil {
|
|
// Log the error but don't return it since this is a deferred function
|
|
fmt.Printf("Error closing connection: %v\n", err)
|
|
}
|
|
}()
|
|
|
|
serviceClient := rpc.NewCacheServiceClient(conn)
|
|
c.cacheServiceClient = serviceClient
|
|
req := schemav1.DeleteRequest{
|
|
Key: key,
|
|
}
|
|
_, err = c.cacheServiceClient.Delete(context.Background(), &req)
|
|
return err
|
|
}
|
|
|
|
func (c *InterplexCache) Exists(key string) bool {
|
|
_, err := c.Load(key)
|
|
return err == nil
|
|
}
|
|
|
|
func (c *InterplexCache) IsCacheDisabled() bool {
|
|
return c.noCache
|
|
}
|
|
|
|
func (c *InterplexCache) GetName() string {
|
|
return "interplex"
|
|
}
|
|
|
|
func (c *InterplexCache) DisableCache() {
|
|
c.noCache = true
|
|
}
|