Skip to content

Commit

Permalink
Merge pull request #425 from robertjsullivan/support-additional-env-v…
Browse files Browse the repository at this point in the history
…ar-types

Support parsing of environment variables other than strings.
  • Loading branch information
sneal authored Jul 18, 2024
2 parents 0ff4362 + 7cf4fa1 commit 66cca9d
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 14 deletions.
15 changes: 7 additions & 8 deletions client/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ package client

import (
"context"
"github.com/cloudfoundry/go-cfclient/v3/resource"
"github.com/stretchr/testify/require"
"net/http"
"testing"

"github.com/cloudfoundry/go-cfclient/v3/resource"
"github.com/cloudfoundry/go-cfclient/v3/testutil"

"github.com/stretchr/testify/require"
)

func TestApps(t *testing.T) {
Expand All @@ -20,11 +19,11 @@ func TestApps(t *testing.T) {
space1 := g.Space().JSON
space2 := g.Space().JSON
org := g.Organization().JSON
appEnvironment := g.AppEnvironment().JSON
appEnvironment := g.AppEnvironment()
appEnvironmentExpected := g.AppEnvironmentExpected(appEnvironment.Name).JSON
appEnvVar := g.AppEnvVar().JSON
appSSH := g.AppSSH().JSON
appPermission := g.AppPermission().JSON

tests := []RouteTest{
{
Description: "Create app",
Expand Down Expand Up @@ -104,10 +103,10 @@ func TestApps(t *testing.T) {
Route: testutil.MockRoute{
Method: "GET",
Endpoint: "/v3/apps/1cb006ee-fb05-47e1-b541-c34179ddc446/env",
Output: g.Single(appEnvironment),
Output: g.Single(appEnvironment.JSON),
Status: http.StatusOK,
},
Expected: appEnvironment,
Expected: appEnvironmentExpected,
Action: func(c *Client, t *testing.T) (any, error) {
return c.Applications.GetEnvironment(context.Background(), "1cb006ee-fb05-47e1-b541-c34179ddc446")
},
Expand Down Expand Up @@ -140,7 +139,7 @@ func TestApps(t *testing.T) {
Output: g.Single(appEnvVar),
Status: http.StatusOK,
},
Expected: `{ "RAILS_ENV": "production" }`,
Expected: `{ "RAILS_ENV": "production", "SOME_BOOLEAN": "true", "SOME_FLOAT64": "10.4", "SOME_INT": "5" }`,
Action: func(c *Client, t *testing.T) (any, error) {
return c.Applications.GetEnvironmentVariables(context.Background(), "1cb006ee-fb05-47e1-b541-c34179ddc446")
},
Expand Down
2 changes: 1 addition & 1 deletion client/revision_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func TestRevisions(t *testing.T) {
Output: g.Single(appEnvVar),
Status: http.StatusOK,
},
Expected: `{ "RAILS_ENV": "production" }`,
Expected: `{ "RAILS_ENV": "production", "SOME_BOOLEAN":"true", "SOME_FLOAT64":"10.4", "SOME_INT":"5" }`,
Action: func(c *Client, t *testing.T) (any, error) {
return c.Revisions.GetEnvironmentVariables(context.Background(), "5a49a370-92cd-4091-bb62-e0914460f7b2")
},
Expand Down
96 changes: 96 additions & 0 deletions resource/app.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package resource

import (
"C"
"encoding/json"
"fmt"
"strconv"
)

type App struct {
Expand Down Expand Up @@ -132,3 +135,96 @@ func NewAppCreate(name, spaceGUID string) *AppCreate {
},
}
}

type InterfaceEnvVar struct {
Var map[string]interface{} `json:"var"`
}

func (f *EnvVar) UnmarshalJSON(b []byte) error {
s := string(b)
if s == "" || s == "\"\"" {
return nil
}

var interfaceEnvVar InterfaceEnvVar

err := json.Unmarshal(b, &interfaceEnvVar)

if err != nil {
return err
}

varMap := make(map[string]*string)
for key, value := range interfaceEnvVar.Var {
switch v := value.(type) {
default:
fmt.Printf("unexpected env var type, skipping env var: %T", v)
continue
case int:
stringVal := strconv.Itoa(v)
varMap[key] = &stringVal
case string:
varMap[key] = &v
case bool:
stringBool := strconv.FormatBool(v)
varMap[key] = &stringBool
case float64:
stringFloat := strconv.FormatFloat(v, 'f', -1, 64)
varMap[key] = &stringFloat
}
}
f.Var = varMap

return nil
}

type InterfaceAppEnvironment struct {
EnvVars map[string]interface{} `json:"environment_variables,omitempty"`
StagingEnv map[string]interface{} `json:"staging_env_json,omitempty"`
RunningEnv map[string]interface{} `json:"running_env_json,omitempty"`
SystemEnvVars map[string]json.RawMessage `json:"system_env_json,omitempty"` // VCAP_SERVICES
AppEnvVars map[string]json.RawMessage `json:"application_env_json,omitempty"` // VCAP_APPLICATION
}

func (f *AppEnvironment) UnmarshalJSON(b []byte) error {
s := string(b)
if s == "" || s == "\"\"" {
return nil
}

var interfaceAppEnvironment InterfaceAppEnvironment

err := json.Unmarshal(b, &interfaceAppEnvironment)

if err != nil {
return err
}

f.EnvVars = convertEnvVars(interfaceAppEnvironment.EnvVars)
f.StagingEnv = convertEnvVars(interfaceAppEnvironment.StagingEnv)
f.RunningEnv = convertEnvVars(interfaceAppEnvironment.RunningEnv)
f.AppEnvVars = interfaceAppEnvironment.AppEnvVars
f.SystemEnvVars = interfaceAppEnvironment.SystemEnvVars

return nil
}

func convertEnvVars(envVars map[string]interface{}) map[string]string {
envVarMap := make(map[string]string)
for key, value := range envVars {
switch v := value.(type) {
default:
fmt.Printf("unexpected env var type, skipping env var: %T", v)
continue
case int:
envVarMap[key] = strconv.Itoa(v)
case string:
envVarMap[key] = v
case bool:
envVarMap[key] = strconv.FormatBool(v)
case float64:
envVarMap[key] = strconv.FormatFloat(v, 'f', -1, 64)
}
}
return envVarMap
}
7 changes: 7 additions & 0 deletions testutil/object_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,13 @@ func (o ObjectJSONGenerator) AppEnvironment() *JSONResource {
return o.renderTemplate(r, "app_environment.json")
}

func (o ObjectJSONGenerator) AppEnvironmentExpected(name string) *JSONResource {
r := &JSONResource{
Name: name,
}
return o.renderTemplate(r, "app_environment_expected.json")
}

func (o ObjectJSONGenerator) AppEnvVar() *JSONResource {
r := &JSONResource{}
return o.renderTemplate(r, "app_envvar.json")
Expand Down
15 changes: 12 additions & 3 deletions testutil/template/app_environment.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
{
"staging_env_json": {
"GEM_CACHE": "http://gem-cache.example.org"
"GEM_CACHE": "http://gem-cache.example.org",
"SOME_BOOLEAN": true,
"SOME_INT": 5,
"SOME_FLOAT64": 10.4
},
"running_env_json": {
"HTTP_PROXY": "http://proxy.example.org"
"HTTP_PROXY": "http://proxy.example.org",
"SOME_BOOLEAN": true,
"SOME_INT": 5,
"SOME_FLOAT64": 10.4
},
"environment_variables": {
"RAILS_ENV": "production"
"RAILS_ENV": "production",
"SOME_BOOLEAN": true,
"SOME_INT": 5,
"SOME_FLOAT64": 10.4
},
"system_env_json": {
"VCAP_SERVICES": {
Expand Down
57 changes: 57 additions & 0 deletions testutil/template/app_environment_expected.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"staging_env_json": {
"GEM_CACHE": "http://gem-cache.example.org",
"SOME_BOOLEAN": "true",
"SOME_INT": "5",
"SOME_FLOAT64": "10.4"
},
"running_env_json": {
"HTTP_PROXY": "http://proxy.example.org",
"SOME_BOOLEAN": "true",
"SOME_INT": "5",
"SOME_FLOAT64": "10.4"
},
"environment_variables": {
"RAILS_ENV": "production",
"SOME_BOOLEAN": "true",
"SOME_INT": "5",
"SOME_FLOAT64": "10.4"
},
"system_env_json": {
"VCAP_SERVICES": {
"mysql": [
{
"name": "db-for-my-app",
"binding_id": "0e85b634-e043-4b43-96da-f83dfe83ab33",
"binding_name": "db-for-my-app",
"instance_id": "07fca01c-f789-4d45-80b4-e19ba3ca862c",
"instance_name": "my-mysql-service",
"label": "mysql",
"tags": ["relational", "sql"],
"plan": "xlarge",
"credentials": {
"username": "user",
"password": "top-secret"
},
"syslog_drain_url": "https://syslog.example.org/drain",
"volume_mounts": [],
"provider": null
}
]
}
},
"application_env_json": {
"VCAP_APPLICATION": {
"limits": {
"fds": 16384
},
"application_name": "{{.Name}}",
"application_uris": [ "{{.Name}}.example.org" ],
"name": "{{.Name}}",
"space_name": "my_space",
"space_id": "2f35885d-0c9d-4423-83ad-fd05066f8576",
"uris": [ "my_app.example.org" ],
"users": null
}
}
}
8 changes: 6 additions & 2 deletions testutil/template/app_envvar.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{
"var": {
"RAILS_ENV": "production"
"RAILS_ENV": "production",
"SOME_BOOLEAN": true,
"SOME_INT": 5,
"SOME_FLOAT64": 10.4
},
"links": {
"self": {
Expand All @@ -10,4 +13,5 @@
"href": "https://api.example.org/v3/apps/[guid]"
}
}
}
}

0 comments on commit 66cca9d

Please sign in to comment.