-
Notifications
You must be signed in to change notification settings - Fork 113
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
[RSDK-8291] Use Global Connection to App in Config Watcher #4773
Changes from 15 commits
72f86e2
e177bbb
5e95983
c911c20
8bc2348
e93dfce
06d6a32
8c867bf
65920bb
868e134
822ed05
cb72f18
3ca75cb
bd6bf7d
d030c30
4eb2805
0d73435
f2d84f5
877c5eb
80556bd
892d072
4b7c683
92f33c5
2264356
0caf8d7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To pass an |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,7 +12,6 @@ import ( | |
"path/filepath" | ||
"runtime" | ||
"sort" | ||
"time" | ||
|
||
"github.com/a8m/envsubst" | ||
"github.com/pkg/errors" | ||
|
@@ -24,6 +23,7 @@ import ( | |
"go.viam.com/rdk/logging" | ||
"go.viam.com/rdk/resource" | ||
rutils "go.viam.com/rdk/utils" | ||
"go.viam.com/rdk/utils/contextutils" | ||
) | ||
|
||
// RDK versioning variables which are replaced by LD flags. | ||
|
@@ -34,9 +34,6 @@ var ( | |
) | ||
|
||
const ( | ||
initialReadTimeout = 1 * time.Second | ||
readTimeout = 5 * time.Second | ||
readTimeoutBehindProxy = time.Minute | ||
// PackagesDirName is where packages go underneath viamDotDir. | ||
PackagesDirName = "packages" | ||
// LocalPackagesSuffix is used by the local package manager. | ||
|
@@ -182,28 +179,6 @@ func isLocationSecretsEqual(prevCloud, cloud *Cloud) bool { | |
return true | ||
} | ||
|
||
// GetTimeoutCtx returns a context [and its cancel function] with a timeout value determined by whether we are behind a proxy and whether a | ||
// cached config exists. | ||
func GetTimeoutCtx(ctx context.Context, shouldReadFromCache bool, id string) (context.Context, func()) { | ||
timeout := readTimeout | ||
// When environment indicates we are behind a proxy, bump timeout. Network | ||
// operations tend to take longer when behind a proxy. | ||
if proxyAddr := os.Getenv(rpc.SocksProxyEnvVar); proxyAddr != "" { | ||
timeout = readTimeoutBehindProxy | ||
} | ||
|
||
// use shouldReadFromCache to determine whether this is part of initial read or not, but only shorten timeout | ||
// if cached config exists | ||
cachedConfigExists := false | ||
if _, err := os.Stat(getCloudCacheFilePath(id)); err == nil { | ||
cachedConfigExists = true | ||
} | ||
if shouldReadFromCache && cachedConfigExists { | ||
timeout = initialReadTimeout | ||
} | ||
return context.WithTimeout(ctx, timeout) | ||
} | ||
|
||
// readFromCloud fetches a robot config from the cloud based | ||
// on the given config. | ||
func readFromCloud( | ||
|
@@ -213,10 +188,11 @@ func readFromCloud( | |
shouldReadFromCache bool, | ||
checkForNewCert bool, | ||
logger logging.Logger, | ||
conn rpc.ClientConn, | ||
) (*Config, error) { | ||
logger.Debug("reading configuration from the cloud") | ||
cloudCfg := originalCfg.Cloud | ||
unprocessedConfig, cached, err := getFromCloudOrCache(ctx, cloudCfg, shouldReadFromCache, logger) | ||
unprocessedConfig, cached, err := getFromCloudOrCache(ctx, cloudCfg, shouldReadFromCache, logger, conn) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
@@ -260,7 +236,7 @@ func readFromCloud( | |
if !cfg.Cloud.SignalingInsecure && (checkForNewCert || tls.certificate == "" || tls.privateKey == "") { | ||
logger.Debug("reading tlsCertificate from the cloud") | ||
|
||
ctxWithTimeout, cancel := GetTimeoutCtx(ctx, shouldReadFromCache, cloudCfg.ID) | ||
ctxWithTimeout, cancel := contextutils.GetTimeoutCtx(ctx, shouldReadFromCache, cloudCfg.ID) | ||
certData, err := readCertificateDataFromCloudGRPC(ctxWithTimeout, cloudCfg, logger) | ||
if err != nil { | ||
cancel() | ||
|
@@ -350,13 +326,14 @@ func Read( | |
ctx context.Context, | ||
filePath string, | ||
logger logging.Logger, | ||
conn rpc.ClientConn, | ||
) (*Config, error) { | ||
buf, err := envsubst.ReadFile(filePath) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return FromReader(ctx, filePath, bytes.NewReader(buf), logger) | ||
return FromReader(ctx, filePath, bytes.NewReader(buf), logger, conn) | ||
} | ||
|
||
// ReadLocalConfig reads a config from the given file but does not fetch any config from the remote servers. | ||
|
@@ -370,7 +347,8 @@ func ReadLocalConfig( | |
return nil, err | ||
} | ||
|
||
return fromReader(ctx, filePath, bytes.NewReader(buf), logger, false) | ||
var nilConn rpc.ClientConn | ||
return fromReader(ctx, filePath, bytes.NewReader(buf), logger, nilConn) | ||
} | ||
|
||
// FromReader reads a config from the given reader and specifies | ||
|
@@ -380,8 +358,9 @@ func FromReader( | |
originalPath string, | ||
r io.Reader, | ||
logger logging.Logger, | ||
conn rpc.ClientConn, | ||
) (*Config, error) { | ||
return fromReader(ctx, originalPath, r, logger, true) | ||
return fromReader(ctx, originalPath, r, logger, conn) | ||
} | ||
|
||
// fromReader reads a config from the given reader and specifies | ||
|
@@ -391,7 +370,7 @@ func fromReader( | |
originalPath string, | ||
r io.Reader, | ||
logger logging.Logger, | ||
shouldReadFromCloud bool, | ||
conn rpc.ClientConn, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you take a look and see if we can replace shouldReadFromCloud with conn entirely? so the existence of a connection itself is the indicator whether a we should be reading from cloud or not totally ok if not a straight swap, just curious There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yep I'll investigate |
||
) (*Config, error) { | ||
// First read and process config from disk | ||
unprocessedConfig := Config{ | ||
|
@@ -406,8 +385,8 @@ func fromReader( | |
return nil, errors.Wrapf(err, "failed to process Config") | ||
} | ||
|
||
if shouldReadFromCloud && cfgFromDisk.Cloud != nil { | ||
cfg, err := readFromCloud(ctx, cfgFromDisk, nil, true, true, logger) | ||
if conn != nil && cfgFromDisk.Cloud != nil { | ||
cfg, err := readFromCloud(ctx, cfgFromDisk, nil, true, true, logger, conn) | ||
return cfg, err | ||
} | ||
|
||
|
@@ -648,13 +627,19 @@ func processConfig(unprocessedConfig *Config, fromCloud bool, logger logging.Log | |
|
||
// getFromCloudOrCache returns the config from the gRPC endpoint. If failures during cloud lookup fallback to the | ||
// local cache if the error indicates it should. | ||
func getFromCloudOrCache(ctx context.Context, cloudCfg *Cloud, shouldReadFromCache bool, logger logging.Logger) (*Config, bool, error) { | ||
func getFromCloudOrCache( | ||
ctx context.Context, | ||
cloudCfg *Cloud, | ||
shouldReadFromCache bool, | ||
logger logging.Logger, | ||
conn rpc.ClientConn, | ||
) (*Config, bool, error) { | ||
var cached bool | ||
|
||
ctxWithTimeout, cancel := GetTimeoutCtx(ctx, shouldReadFromCache, cloudCfg.ID) | ||
ctxWithTimeout, cancel := contextutils.GetTimeoutCtx(ctx, shouldReadFromCache, cloudCfg.ID) | ||
defer cancel() | ||
|
||
cfg, errorShouldCheckCache, err := getFromCloudGRPC(ctxWithTimeout, cloudCfg, logger) | ||
cfg, errorShouldCheckCache, err := getFromCloudGRPC(ctxWithTimeout, cloudCfg, logger, conn) | ||
if err != nil { | ||
if shouldReadFromCache && errorShouldCheckCache { | ||
cachedConfig, cacheErr := readFromCache(cloudCfg.ID) | ||
|
@@ -687,15 +672,9 @@ func getFromCloudOrCache(ctx context.Context, cloudCfg *Cloud, shouldReadFromCac | |
} | ||
|
||
// getFromCloudGRPC actually does the fetching of the robot config from the gRPC endpoint. | ||
func getFromCloudGRPC(ctx context.Context, cloudCfg *Cloud, logger logging.Logger) (*Config, bool, error) { | ||
func getFromCloudGRPC(ctx context.Context, cloudCfg *Cloud, logger logging.Logger, conn rpc.ClientConn) (*Config, bool, error) { | ||
shouldCheckCacheOnFailure := true | ||
|
||
conn, err := CreateNewGRPCClient(ctx, cloudCfg, logger) | ||
if err != nil { | ||
return nil, shouldCheckCacheOnFailure, errors.WithMessage(err, "error creating cloud grpc client") | ||
} | ||
defer utils.UncheckedErrorFunc(conn.Close) | ||
|
||
agentInfo, err := getAgentInfo(logger) | ||
if err != nil { | ||
return nil, shouldCheckCacheOnFailure, errors.WithMessage(err, "error getting agent info") | ||
|
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.
[nit] You might've used this pattern elsewhere, but I often see
nil
passed instead of an "empty" struct when we want to communicate to another function that we have no special object for that function to use and it should create its own. Hypothetically, I'd have a small preference for passingnil
here and not&grpc.AppConn
.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.
Done! I like this I for some reason glossed over this as an option when trying to figure how to make it apparent that the code path followed by the tests with an empty connection struct didn't actually need/use the conn so I like this