/
env.go
172 lines (144 loc) · 4.74 KB
/
env.go
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
// Copyright 2012-2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
package context
import (
"fmt"
"os"
"github.com/juju/os/v2/series"
jujuos "github.com/juju/juju/core/os"
)
// Environmenter represent the os environ interface for fetching host level environment
// variables.
type Environmenter interface {
// Environ returns a copy of strings representing the environment, in the
// form "key=value"
Environ() []string
// Getenv retrieves the value of the environment variable named by the key.
// It returns the value, which will be empty if the variable is not present.
Getenv(string) string
// LookupEnv retrieves the value of the environment variable named by the
// key. If the variable is present in the environment the value (which may
// be empty) is returned and the boolean is true. Otherwise the returned
// value will be empty and the boolean will be false.
LookupEnv(string) (string, bool)
}
type EnvironmentWrapper struct {
environFn func() []string
getenvFn func(string) string
lookupEnvFn func(string) (string, bool)
}
// ContextAllowedEnvVars defines a list of allowed env vars to include from the
// given context
var ContextAllowedEnvVars = []string{
// List of Kubernetes env vars to include
"KUBERNETES_PORT",
"KUBERNETES_PORT_443_TCP",
"KUBERNETES_PORT_443_TCP_ADDR",
"KUBERNETES_PORT_443_TCP_PORT",
"KUBERNETES_PORT_443_TCP_PROTO",
"KUBERNETES_SERVICE",
"KUBERNETES_SERVICE_HOST",
"KUBERNETES_SERVICE_PORT",
"KUBERNETES_SERVICE_PORT_HTTPS",
}
// NewHostEnvironmenter constructs an EnvironmentWrapper target at the current
// process host
func NewHostEnvironmenter() *EnvironmentWrapper {
return &EnvironmentWrapper{
environFn: os.Environ,
getenvFn: os.Getenv,
lookupEnvFn: os.LookupEnv,
}
}
// NewRemoveEnvironmenter constructs an EnviornmentWrapper with targets set to
// that of the functions provided.
func NewRemoteEnvironmenter(
environFn func() []string,
getenvFn func(string) string,
lookupEnvFn func(string) (string, bool),
) *EnvironmentWrapper {
return &EnvironmentWrapper{
environFn: environFn,
getenvFn: getenvFn,
lookupEnvFn: lookupEnvFn,
}
}
// Environ implements Environmenter Environ
func (e *EnvironmentWrapper) Environ() []string {
return e.environFn()
}
// Getenv implements Environmenter Getenv
func (e *EnvironmentWrapper) Getenv(key string) string {
return e.getenvFn(key)
}
// LookupEnv implements Environmenter LookupEnv
func (e *EnvironmentWrapper) LookupEnv(key string) (string, bool) {
return e.lookupEnvFn(key)
}
// ContextDependentEnvVars returns the context aware enviormnent variables
// needed for charms depending on contexts they may be operating in.
// For example returning defined Kubernetes env variables when they're defined.
func ContextDependentEnvVars(env Environmenter) []string {
rval := make([]string, 0, len(ContextAllowedEnvVars))
for _, envKey := range ContextAllowedEnvVars {
if val, exists := env.LookupEnv(envKey); exists {
rval = append(rval, fmt.Sprintf("%s=%s", envKey, val))
}
}
return rval
}
// OSDependentEnvVars returns the OS-dependent environment variables that
// should be set for a hook context.
func OSDependentEnvVars(paths Paths, env Environmenter) []string {
switch jujuos.HostOS() {
case jujuos.Ubuntu:
return ubuntuEnv(paths, env)
case jujuos.CentOS:
return centosEnv(paths, env)
case jujuos.GenericLinux:
return genericLinuxEnv(paths, env)
}
return nil
}
func appendPath(paths Paths, env Environmenter) []string {
return []string{
"PATH=" + paths.GetToolsDir() + ":" + env.Getenv("PATH"),
}
}
func ubuntuEnv(paths Paths, envVars Environmenter) []string {
path := appendPath(paths, envVars)
env := []string{
"APT_LISTCHANGES_FRONTEND=none",
"DEBIAN_FRONTEND=noninteractive",
"LANG=C.UTF-8",
"TERM=tmux-256color",
}
return append(env, path...)
}
func centosEnv(paths Paths, envVars Environmenter) []string {
path := appendPath(paths, envVars)
env := []string{
"LANG=C.UTF-8",
}
env = append(env, path...)
// versions older than 7 are not supported and centos7 does not have patch 20150502 for ncurses 5.9
// with terminal definitions for "tmux" and "tmux-256color"
hostSeries, err := series.HostSeries()
if err == nil && hostSeries == "centos7" {
env = append(env, "TERM=screen-256color")
} else {
env = append(env, "TERM=tmux-256color")
}
return env
}
func genericLinuxEnv(paths Paths, envVars Environmenter) []string {
path := appendPath(paths, envVars)
env := []string{
"LANG=C.UTF-8",
}
env = append(env, path...)
// use the "screen" terminal definition (added to ncurses in 1997) on a generic Linux to avoid
// any ncurses version discovery code. tmux documentation suggests that the "screen" terminal is supported.
env = append(env, "TERM=screen")
return env
}