-
Notifications
You must be signed in to change notification settings - Fork 19
Expand file tree
/
Copy pathcfenv.go
More file actions
102 lines (82 loc) · 2.83 KB
/
Copy pathcfenv.go
File metadata and controls
102 lines (82 loc) · 2.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// Package cfenv provides information about the current app deployed on Cloud Foundry, including any bound service(s).
package cfenv
import (
"encoding/json"
"fmt"
"os"
"strconv"
"strings"
"github.com/go-viper/mapstructure/v2"
)
// New creates a new App with the provided environment.
func New(env map[string]string) (*App, error) {
var app App
appVar := env["VCAP_APPLICATION"]
if err := json.Unmarshal([]byte(appVar), &app); err != nil {
return nil, err
}
// duplicate the InstanceID to the previously named ID field for backwards
// compatibility
app.ID = app.InstanceID
app.Home = env["HOME"]
app.MemoryLimit = env["MEMORY_LIMIT"]
if port, err := strconv.Atoi(env["PORT"]); err == nil {
app.Port = port
}
app.WorkingDir = env["PWD"]
app.TempDir = env["TMPDIR"]
app.User = env["USER"]
servicesDoc, err := servicesJSON(env)
if err != nil {
return nil, err
}
var rawServices map[string]interface{}
if err := json.Unmarshal(servicesDoc, &rawServices); err != nil {
return nil, err
}
services := make(map[string][]Service)
for key, value := range rawServices {
var serviceInstances []Service
if err := mapstructure.WeakDecode(value, &serviceInstances); err != nil {
return nil, err
}
services[key] = serviceInstances
}
app.Services = services
return &app, nil
}
// servicesJSON returns the raw service bindings document, read from the file
// named by VCAP_SERVICES_FILE_PATH when that is set and from VCAP_SERVICES
// otherwise.
//
// Cloud Foundry sets one or the other, never both: with the
// file-based-vcap-services app feature enabled it provides only the file path,
// which is how bindings too large for an environment variable are delivered
// (RFC-0030). The file wins here, so the tie only matters in a synthetic
// environment.
//
// A file path that cannot be read is an error rather than a fall back to
// VCAP_SERVICES. On a file-based app that variable is unset, so falling back
// would hand the caller an app with no services and no explanation.
func servicesJSON(env map[string]string) ([]byte, error) {
path := env["VCAP_SERVICES_FILE_PATH"]
if path == "" {
return []byte(env["VCAP_SERVICES"]), nil
}
// The whole point of the feature is to read the path the platform hands
// us, so the path is necessarily a variable.
// #nosec G304
contents, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("reading VCAP_SERVICES_FILE_PATH %q: %w", path, err)
}
return contents, nil
}
// Current creates a new App with the current environment; returns an error if the current environment is not a Cloud Foundry environment.
func Current() (*App, error) {
return New(CurrentEnv())
}
// IsRunningOnCF returns true if the current environment is Cloud Foundry and false if it is not Cloud Foundry.
func IsRunningOnCF() bool {
return strings.TrimSpace(os.Getenv("VCAP_APPLICATION")) != ""
}