forked from cloudfoundry-community/cf-resource
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixes cloudfoundry-community#29 allow setting environment variables i…
…ncluding CF_DIAL_TIMEOUT **Why** Using the `cf` resource in a pipeline which has a high latency connection to the CloudFoundry instance fails and the solution is to set the `CF_DIAL_TIMEOUT` to a higher value (15s is recommended). For instance, this occurs running a Concourse pipeline in AWS Sydney and targeting PWS in the US. By extension, there is no mechanism for setting any of the `CF_` environment variables (or other environment variables if they were needed). **How** The design of the solution has taken a general 'allow shell environment setting' approach as opposed to a 'create individual config params for all CF_ switches'. This is to remove the burden of keeping this resource in sync with the `cf` command line tool while giving the benefit of easy environment config. The solution adds a `CommandEnvironmentVariables` struct to the `Source` struct, allowing a map of environment key-value pairs to be added in to the Source Configuration YAML. A new CfEnvironment struct is used to hold the internal model of the environment variables. There are constructors to pre-populated with environment variables or not. Both constructors pre-populate `CF_COLOR=true` as before. The CloudFoundry struct is now composed of a CfEnvironment. The CfEnvironment uses a `map[string]string' but the JSON Unmarshalling uses a `map[string]interface{}` for ease of type safety, so there is a bit of `fmt.Sprintf("%v", v)` code for handling the conversion. The `CommandEnvironmentVariables` is populated by the `main` during JSON wrangling and then added to the `cloudFoundry`. The environment is finally set up (as before) in the `CloudFoundry.cf` method. **Effects** Any environment variables may be now set for the runtime environment of the `cf` command via the Source Configuration YAML. Existing set variable can be overridden. This is why a `map` was used internally rather than `[]string` of `KEY=VAL` that os.Environ() returns and `cmd.Env` takes.
- Loading branch information
1 parent
a4252bf
commit 0ed3201
Showing
10 changed files
with
264 additions
and
4 deletions.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,3 +27,13 @@ _testmain.go | |
/test.json | ||
/*.tar.gz | ||
/built* | ||
|
||
# IDE | ||
*.iml | ||
.idea | ||
.idea/**/* | ||
*.swp | ||
**/build | ||
|
||
# OSX | ||
**/.DS_Store |
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 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,66 @@ | ||
package out | ||
|
||
import ( | ||
"strings" | ||
"os" | ||
"fmt" | ||
) | ||
|
||
type CfEnvironment struct { | ||
env map[string]string | ||
} | ||
|
||
func NewCfEnvironment() *CfEnvironment { | ||
env := make(map[string]string) | ||
env["CF_COLOR"]="true" | ||
|
||
cfe := &CfEnvironment{env} | ||
|
||
return cfe | ||
} | ||
|
||
func NewCfEnvironmentFromOS() *CfEnvironment { | ||
cfe := NewCfEnvironment() | ||
|
||
osEnvironment := SplitKeyValueStringArrayInToMap(os.Environ()) | ||
cfe.AddEnvironmentVariable(osEnvironment) | ||
|
||
return cfe | ||
} | ||
|
||
func SplitKeyValueStringArrayInToMap(data []string) map[string]interface{} { | ||
items := make(map[string]interface{}) | ||
for _, item := range data { | ||
key, val := SplitKeyValueString(item) | ||
items[key] = val | ||
} | ||
return items | ||
} | ||
|
||
func SplitKeyValueString(item string)(key, val string) { | ||
splits := strings.SplitN(item, "=", 2) | ||
key = splits[0] | ||
val = splits[1] | ||
return | ||
} | ||
|
||
|
||
func (cfe *CfEnvironment) addEnvironmentVariable(key, value string) { | ||
cfe.env[key] = value | ||
} | ||
|
||
func (cfe *CfEnvironment) Environment() []string { | ||
var commandEnvironment []string | ||
|
||
for k, v := range cfe.env { | ||
commandEnvironment = append(commandEnvironment, k+"="+v) | ||
} | ||
return commandEnvironment | ||
} | ||
|
||
func (cfe *CfEnvironment) AddEnvironmentVariable(switchMap map[string]interface{}) { | ||
for k, v := range switchMap { | ||
vString := fmt.Sprintf("%v", v) | ||
cfe.env[k] = vString | ||
} | ||
} |
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,125 @@ | ||
package out_test | ||
|
||
import ( | ||
"github.com/concourse/cf-resource/out" | ||
|
||
. "github.com/onsi/ginkgo" | ||
. "github.com/onsi/gomega" | ||
"os" | ||
) | ||
|
||
var oneEnvironmentPair = map[string]interface{}{"ENV_ONE": "env_one"} | ||
|
||
// json from config is unmarshalled in to map[string]interface{} | ||
// keys are always strings, but values can be anything | ||
var multipleEnvironmentPairs = map[string]interface{}{ | ||
"ENV_ONE": "env_one", | ||
"ENV_TWO": 2, | ||
"ENV_THREE": true, | ||
} | ||
var fiveEnvironmentPair = map[string]interface{}{"ENV_FIVE": "env_five"} | ||
|
||
var _ = Describe("utility functions", func() { | ||
Context("happy path", func() { | ||
|
||
osLikeKVArray := []string{ | ||
"OS_ONE=one", | ||
"OS_TWO=two", | ||
"OS_THREE=three", | ||
} | ||
|
||
simpleKVString := "SIMPLE=pair" | ||
keyWithValueContainingEqualsString := "EQUAL_VALUE=val_key=val_val" | ||
|
||
It("simple k=v string splits correctly", func() { | ||
key, value := out.SplitKeyValueString(simpleKVString) | ||
|
||
Ω(key).Should(Equal("SIMPLE")) | ||
Ω(value).Should(Equal("pair")) | ||
}) | ||
|
||
It("value containing equal is parsed correctly (needs `SplitN()`)", func() { | ||
key, value := out.SplitKeyValueString(keyWithValueContainingEqualsString) | ||
|
||
Ω(key).Should(Equal("EQUAL_VALUE")) | ||
Ω(value).Should(Equal("val_key=val_val")) | ||
}) | ||
|
||
It("array of k=v strings split correctly in to map", func() { | ||
kvMap := out.SplitKeyValueStringArrayInToMap(osLikeKVArray) | ||
|
||
Ω(kvMap).Should(HaveLen(3)) | ||
Ω(kvMap).Should(HaveKeyWithValue("OS_ONE", "one")) | ||
Ω(kvMap).Should(HaveKeyWithValue("OS_TWO", "two")) | ||
Ω(kvMap).Should(HaveKeyWithValue("OS_THREE", "three")) | ||
}) | ||
}) | ||
}) | ||
|
||
var _ = Describe("CfEnvironment from Empty", func() { | ||
Context("happy path", func() { | ||
var cfEnvironment *out.CfEnvironment | ||
|
||
BeforeEach(func() { | ||
cfEnvironment = out.NewCfEnvironment() | ||
}) | ||
|
||
It("default command environment should ONLY contain CF_COLOR=true", func() { | ||
cfEnv := cfEnvironment.Environment() | ||
Ω(cfEnv).Should(HaveLen(1)) | ||
Ω(cfEnv).Should(ContainElement("CF_COLOR=true")) | ||
}) | ||
|
||
It("added environment switch ends up in environment", func() { | ||
|
||
cfEnvironment.AddEnvironmentVariable(oneEnvironmentPair) | ||
cfEnv := cfEnvironment.Environment() | ||
|
||
Ω(cfEnv).Should(HaveLen(2)) | ||
Ω(cfEnv).Should(ContainElement("ENV_ONE=env_one")) | ||
}) | ||
|
||
It("multiple environment switches all end up in environment", func() { | ||
|
||
cfEnvironment.AddEnvironmentVariable(multipleEnvironmentPairs) | ||
cfEnv := cfEnvironment.Environment() | ||
|
||
Ω(cfEnv).Should(HaveLen(4)) | ||
Ω(cfEnv).Should(ContainElement("ENV_ONE=env_one")) | ||
Ω(cfEnv).Should(ContainElement("ENV_TWO=2")) | ||
Ω(cfEnv).Should(ContainElement("ENV_THREE=true")) | ||
}) | ||
|
||
It("multiple adds to environment retains all additions", func() { | ||
cfEnvironment.AddEnvironmentVariable(multipleEnvironmentPairs) | ||
cfEnvironment.AddEnvironmentVariable(fiveEnvironmentPair) | ||
cfEnv := cfEnvironment.Environment() | ||
|
||
Ω(cfEnv).Should(HaveLen(5)) | ||
Ω(cfEnv).Should(ContainElement("ENV_ONE=env_one")) | ||
Ω(cfEnv).Should(ContainElement("ENV_TWO=2")) | ||
Ω(cfEnv).Should(ContainElement("ENV_THREE=true")) | ||
|
||
Ω(cfEnv).Should(ContainElement("ENV_FIVE=env_five")) | ||
}) | ||
|
||
}) | ||
}) | ||
|
||
var _ = Describe("CfEnvironment from OS", func() { | ||
Context("happy path", func() { | ||
var cfEnvironment *out.CfEnvironment | ||
env := os.Environ() | ||
baseExpectedEnvVariables := len(env) + 1 | ||
|
||
BeforeEach(func() { | ||
cfEnvironment = out.NewCfEnvironmentFromOS() | ||
}) | ||
|
||
It("default command environment should contain CF_COLOR=true", func() { | ||
cfEnv := cfEnvironment.Environment() | ||
Ω(cfEnv).Should(HaveLen(baseExpectedEnvVariables)) | ||
Ω(cfEnv).Should(ContainElement("CF_COLOR=true")) | ||
}) | ||
}) | ||
}) |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package out_test | ||
|
||
import ( | ||
"github.com/concourse/cf-resource/out" | ||
|
||
. "github.com/onsi/ginkgo" | ||
. "github.com/onsi/gomega" | ||
"os" | ||
) | ||
|
||
var _ = Describe("CloudFoundry", func() { | ||
Context("happy path", func() { | ||
var cf *out.CloudFoundry | ||
env := os.Environ() | ||
baseExpectedEnvVariableCount := len(env) + 1 | ||
|
||
BeforeEach(func() { | ||
cf = out.NewCloudFoundry() | ||
}) | ||
|
||
It("default command environment should contain CF_COLOR=true", func() { | ||
cfEnv := cf.CommandEnvironment().Environment() | ||
Ω(cfEnv).Should(HaveLen(baseExpectedEnvVariableCount)) | ||
Ω(cfEnv).Should(ContainElement("CF_COLOR=true")) | ||
}) | ||
}) | ||
}) |
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