Skip to content
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

GODRIVER-2906 [master] Add container Env to Handshake. #1397

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 79 additions & 16 deletions x/mongo/driver/operation/hello.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,12 +153,23 @@ const (
envNameVercel = "vercel"
)

const dockerEnvPath = "/.dockerenv"
const envVarK8s = "KUBERNETES_SERVICE_HOST"

const (
// Runtime names
runtimeNameDocker = "docker"

// Orchestrator names
orchestratorNameK8s = "kubernetes"
)

// getFaasEnvName parses the FaaS environment variable name and returns the
// corresponding name used by the client. If none of the variables or variables
// for multiple names are populated the client.env value MUST be entirely
// omitted. When variables for multiple "client.env.name" values are present,
// "vercel" takes precedence over "aws.lambda"; any other combination MUST cause
// "client.env" to be entirely omitted.
// for multiple names are populated the FaaS values MUST be entirely omitted.
// When variables for multiple "client.env.name" values are present, "vercel"
// takes precedence over "aws.lambda"; any other combination MUST cause FaaS
// values to be entirely omitted.
func getFaasEnvName() string {
envVars := []string{
envVarAWSExecutionEnv,
Expand Down Expand Up @@ -218,6 +229,31 @@ func getFaasEnvName() string {
return ""
}

type containerInfo struct {
runtime string
orchestrator string
}

// getContainerEnvInfo returns runtime and orchestrator of a container.
// If no fields is populated, the client.env.container value MUST be entirely
// omitted.
func getContainerEnvInfo() *containerInfo {
var runtime, orchestrator string
if _, err := os.Stat(dockerEnvPath); !os.IsNotExist(err) {
runtime = runtimeNameDocker
}
if v := os.Getenv(envVarK8s); v != "" {
orchestrator = orchestratorNameK8s
}
if runtime != "" || orchestrator != "" {
return &containerInfo{
runtime: runtime,
orchestrator: orchestrator,
}
}
return nil
}

// appendClientAppName appends the application metadata to the dst. It is the
// responsibility of the caller to check that this appending does not cause dst
// to exceed any size limitations.
Expand Down Expand Up @@ -256,14 +292,20 @@ func appendClientEnv(dst []byte, omitNonName, omitDoc bool) ([]byte, error) {
}

name := getFaasEnvName()
if name == "" {
container := getContainerEnvInfo()
// Omit the entire 'env' if both name and container are empty because other
// fields depend on either of them.
if name == "" && container == nil {
return dst, nil
}

var idx int32

idx, dst = bsoncore.AppendDocumentElementStart(dst, "env")
dst = bsoncore.AppendStringElement(dst, "name", name)

if name != "" {
dst = bsoncore.AppendStringElement(dst, "name", name)
}

addMem := func(envVar string) []byte {
mem := os.Getenv(envVar)
Expand Down Expand Up @@ -306,6 +348,7 @@ func appendClientEnv(dst []byte, omitNonName, omitDoc bool) ([]byte, error) {
}

if !omitNonName {
// No other FaaS fields will be populated if the name is empty.
switch name {
case envNameAWSLambda:
dst = addMem(envVarAWSLambdaFunctionMemorySize)
Expand All @@ -319,6 +362,22 @@ func appendClientEnv(dst []byte, omitNonName, omitDoc bool) ([]byte, error) {
}
}

if container != nil {
var idxCntnr int32
idxCntnr, dst = bsoncore.AppendDocumentElementStart(dst, "container")
if container.runtime != "" {
dst = bsoncore.AppendStringElement(dst, "runtime", container.runtime)
}
if container.orchestrator != "" {
dst = bsoncore.AppendStringElement(dst, "orchestrator", container.orchestrator)
}
var err error
dst, err = bsoncore.AppendDocumentEnd(dst, idxCntnr)
if err != nil {
return dst, err
}
}

return bsoncore.AppendDocumentEnd(dst, idx)
}

Expand Down Expand Up @@ -358,21 +417,25 @@ func appendClientPlatform(dst []byte) []byte {
// name: "<string>"
// },
// driver: {
// name: "<string>",
// version: "<string>"
// name: "<string>",
// version: "<string>"
// },
// platform: "<string>",
// os: {
// type: "<string>",
// name: "<string>",
// architecture: "<string>",
// version: "<string>"
// type: "<string>",
// name: "<string>",
// architecture: "<string>",
// version: "<string>"
// },
// env: {
// name: "<string>",
// timeout_sec: 42,
// memory_mb: 1024,
// region: "<string>",
// name: "<string>",
// timeout_sec: 42,
// memory_mb: 1024,
// region: "<string>",
// container: {
// runtime: "<string>",
// orchestrator: "<string>"
// }
// }
// }
func encodeClientMetadata(appname string, maxLen int) ([]byte, error) {
Expand Down
50 changes: 43 additions & 7 deletions x/mongo/driver/operation/hello_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,14 @@ func TestAppendClientEnv(t *testing.T) {
},
want: []byte(`{"env":{"name":"azure.func"}}`),
},
{
name: "k8s",
env: map[string]string{
envVarK8s: "0.0.0.0",
},
want: []byte(`{"env":{"container":{"orchestrator":"kubernetes"}}}`),
},
// client.env.container.runtime is untested.
}

for _, test := range tests {
Expand Down Expand Up @@ -382,11 +390,17 @@ func TestEncodeClientMetadata(t *testing.T) {
Architecture string `bson:"architecture,omitempty"`
}

type container struct {
Runtime string `bson:"runtime,omitempty"`
Orchestrator string `bson:"orchestrator,omitempty"`
}

type env struct {
Name string `bson:"name,omitempty"`
TimeoutSec int64 `bson:"timeout_sec,omitempty"`
MemoryMB int32 `bson:"memory_mb,omitempty"`
Region string `bson:"region,omitempty"`
Name string `bson:"name,omitempty"`
TimeoutSec int64 `bson:"timeout_sec,omitempty"`
MemoryMB int32 `bson:"memory_mb,omitempty"`
Region string `bson:"region,omitempty"`
Container *container `bson:"container,omitempty"`
}

type clientMetadata struct {
Expand All @@ -408,6 +422,7 @@ func TestEncodeClientMetadata(t *testing.T) {
t.Setenv(envVarAWSLambdaRuntimeAPI, "lambda")
t.Setenv(envVarAWSLambdaFunctionMemorySize, "123")
t.Setenv(envVarAWSRegion, "us-east-2")
t.Setenv(envVarK8s, "0.0.0.0")

t.Run("nothing is omitted", func(t *testing.T) {
got, err := encodeClientMetadata("foo", maxClientMetadataSize)
Expand All @@ -418,7 +433,14 @@ func TestEncodeClientMetadata(t *testing.T) {
Driver: &driver{Name: driverName, Version: version.Driver},
OS: &dist{Type: runtime.GOOS, Architecture: runtime.GOARCH},
Platform: runtime.Version(),
Env: &env{Name: envNameAWSLambda, MemoryMB: 123, Region: "us-east-2"},
Env: &env{
Name: envNameAWSLambda,
MemoryMB: 123,
Region: "us-east-2",
Container: &container{
Orchestrator: "kubernetes",
},
},
})

assertDocsEqual(t, got, want)
Expand All @@ -437,7 +459,12 @@ func TestEncodeClientMetadata(t *testing.T) {
Driver: &driver{Name: driverName, Version: version.Driver},
OS: &dist{Type: runtime.GOOS, Architecture: runtime.GOARCH},
Platform: runtime.Version(),
Env: &env{Name: envNameAWSLambda},
Env: &env{
Name: envNameAWSLambda,
Container: &container{
Orchestrator: "kubernetes",
},
},
})

assertDocsEqual(t, got, want)
Expand All @@ -454,6 +481,10 @@ func TestEncodeClientMetadata(t *testing.T) {

// Calculate what the env.name costs.
ndst := bsoncore.AppendStringElement(nil, "name", envNameAWSLambda)
idx, ndst := bsoncore.AppendDocumentElementStart(ndst, "container")
ndst = bsoncore.AppendStringElement(ndst, "orchestrator", "kubernetes")
ndst, err = bsoncore.AppendDocumentEnd(ndst, idx)
require.NoError(t, err)

// Environment sub name.
envSubName := len(edst) - len(ndst)
Expand All @@ -466,7 +497,12 @@ func TestEncodeClientMetadata(t *testing.T) {
Driver: &driver{Name: driverName, Version: version.Driver},
OS: &dist{Type: runtime.GOOS},
Platform: runtime.Version(),
Env: &env{Name: envNameAWSLambda},
Env: &env{
Name: envNameAWSLambda,
Container: &container{
Orchestrator: "kubernetes",
},
},
})

assertDocsEqual(t, got, want)
Expand Down
Loading