-
Notifications
You must be signed in to change notification settings - Fork 173
/
config.go
252 lines (196 loc) · 9.04 KB
/
config.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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
// Copyright 2016 VMware, Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package tether
import (
"io"
"net"
"os"
"os/exec"
"sync"
log "github.com/Sirupsen/logrus"
"github.com/vmware/vic/lib/config/executor"
"github.com/vmware/vic/pkg/dio"
"github.com/vmware/vic/pkg/ip"
)
type ExecutorConfig struct {
// allow us to lock the maps when config is being updated
// subelements tend to have their own locks
sync.Mutex
// The name of the system
Name string `vic:"0.1" scope:"read-only" key:"common/name"`
// ID corresponds to that of the primary session
ID string `vic:"0.1" scope:"read-only" key:"common/id"`
// Debug is a numeric level that controls extent of debugging
DebugLevel int `vic:"0.1" scope:"read-only" key:"diagnostics/debug"`
// Exclusive access to childPidTable
pidMutex sync.Mutex `vic:"0.1" scope:"read-only" recurse:"depth=0"`
// Set of child PIDs created by us.
pids map[int]*SessionConfig `vic:"0.1" scope:"read-only" recurse:"depth=0"`
// Sessions is the set of sessions currently hosted by this executor
// These are keyed by session ID
Sessions map[string]*SessionConfig `vic:"0.1" scope:"read-only" key:"sessions"`
// Execs is the set of non-persistent sessions hosted by this executor
Execs map[string]*SessionConfig `vic:"0.1" scope:"read-only,non-persistent" key:"execs"`
// Maps the mount name to the detail mount specification
Mounts map[string]executor.MountSpec `vic:"0.1" scope:"read-only" key:"mounts"`
// This describes an executors presence on a network, and contains sufficient
// information to configure the interface in the guest.
Networks map[string]*NetworkEndpoint `vic:"0.1" scope:"read-only" key:"networks"`
// Key is the host key used during communicate back with the Interaction endpoint if any
// Used if the in-guest tether is responsible for authenticating the connection
Key []byte `vic:"0.1" scope:"read-only" key:"key"`
// AsymmetricRouting is set to true if the VCH needs to be setup for asymmetric routing
AsymmetricRouting bool `vic:"0.1" scope:"read-only" key:"asymrouting"`
// Hostname and domainname provided by personality
Hostname string `vic:"0.1" scope:"read-only" key:"hostname"`
Domainname string `vic:"0.1" scope:"read-only" key:"domainname"`
}
// SessionConfig defines the content of a session - this maps to the root of a process tree
// inside an executor
// This is close to but not perfectly aligned with the new docker/docker/daemon/execdriver/driver:CommonProcessConfig
type SessionConfig struct {
// Protects the structure
sync.Mutex `vic:"0.1" scope:"read-only" recurse:"depth=0"`
// The primary session may have the same ID as the executor owning it
executor.Common `vic:"0.1" scope:"read-only" key:"common"`
Detail `vic:"0.1" scope:"read-write" key:"detail"`
// Diagnostics holds basic diagnostics data
Diagnostics executor.Diagnostics `vic:"0.1" scope:"read-write" key:"diagnostics"`
// The primary process for the session
Cmd exec.Cmd `vic:"0.1" scope:"read-only" key:"cmd" recurse:"depth=2,nofollow"`
// The exit status of the process, if any
ExitStatus int `vic:"0.1" scope:"read-write" key:"status" recurse:"skip-decode"`
Started string `vic:"0.1" scope:"read-write" key:"started" recurse:"skip-decode"`
// Allow attach
Attach bool `vic:"0.1" scope:"read-only" key:"attach"`
OpenStdin bool `vic:"0.1" scope:"read-only" key:"openstdin"`
// Delay launching the Cmd until an attach request comes
RunBlock bool `vic:"0.1" scope:"read-write" key:"runblock"`
// Should this config be activated or not
Active bool `vic:"0.1" scope:"read-only" key:"active"`
// Allocate a tty or not
Tty bool `vic:"0.1" scope:"read-only" key:"tty"`
// Restart controls whether a process gets relaunched if it exists
Restart bool `vic:"0.1" scope:"read-only" key:"restart"`
// StopSignal is the signal name or number used to stop a container
StopSignal string `vic:"0.1" scope:"read-only" key:"stopSignal"`
// User and group for setuid programs
User string `vic:"0.1" scope:"read-only" key:"user"`
Group string `vic:"0.1" scope:"read-only" key:"group"`
// if there's a pty then we need additional management data
Pty *os.File `vic:"0.1" scope:"read-only" recurse:"depth=0"`
Outwriter dio.DynamicMultiWriter `vic:"0.1" scope:"read-only" recurse:"depth=0"`
Errwriter dio.DynamicMultiWriter `vic:"0.1" scope:"read-only" recurse:"depth=0"`
Reader dio.DynamicMultiReader `vic:"0.1" scope:"read-only" recurse:"depth=0"`
StdinPipe io.WriteCloser `vic:"0.1" scope:"read-only" recurse:"depth=0"`
StdoutPipe io.ReadCloser `vic:"0.1" scope:"read-only" recurse:"depth=0"`
StderrPipe io.ReadCloser `vic:"0.1" scope:"read-only" recurse:"depth=0"`
// Blocks launching the process.
// The channel contains no value; we’re only interested in its closed property.
ClearToLaunch chan struct{} `vic:"0.1" scope:"read-only" recurse:"depth=0"`
once sync.Once
wait *sync.WaitGroup
// record the config prefix associated with this session - allows partial encoding
// without hardcoding the sessions parent in the config.
// This is basically a workaround for:
// a. not having integrated Exec sessions in to the Sessions map
// b. having only an implementation of CalculateKeys that requires a prefix instead
// of performing a search
extraconfigKey string
}
type NetworkEndpoint struct {
// Common.Name - the nic alias requested (only one name and one alias possible in linux)
// Common.ID - pci slot of the vnic allowing for interface identifcation in-guest
executor.Common
// Whether this endpoint's IP was specified by the client (true if it was)
Static bool `vic:"0.1" scope:"read-only" key:"static"`
// IP address to assign
IP *net.IPNet `vic:"0.1" scope:"read-only" key:"ip"`
// Actual IP address assigned
Assigned net.IPNet `vic:"0.1" scope:"read-write" key:"assigned"`
// The network in which this information should be interpreted. This is embedded directly rather than
// as a pointer so that we can ensure the data is consistent
Network executor.ContainerNetwork `vic:"0.1" scope:"read-only" key:"network"`
// DHCP runtime info
DHCP *DHCPInfo `vic:"0.1" scope:"read-only" recurse:"depth=0"`
Ports []string `vic:"0.1" scope:"read-only" key:"ports"`
// is this endpoint connected to an internal network?
Internal bool `vic:"0.1" scope:"read-only" key:"internal"`
// whether the network config was successfully applied
configured bool `vic:"0.1" scope:"read-only" recurse:"depth=0"`
}
type Detail struct {
// creation, started & stopped timestamps
CreateTime int64 `vic:"0.1" scope:"read-write" key:"createtime"`
StartTime int64 `vic:"0.1" scope:"read-write" key:"starttime" recurse:"skip-decode"`
StopTime int64 `vic:"0.1" scope:"read-write" key:"stoptime" recurse:"skip-decode"`
}
func (e *NetworkEndpoint) IsDynamic() bool {
return !e.Static && (e.IP == nil || ip.IsUnspecifiedIP(e.IP.IP))
}
type DHCPInfo struct {
Assigned net.IPNet
Nameservers []net.IP
Gateway net.IPNet
}
// block sets the blocking behaviour of session launches to the argument.
// does NOT take a lock
func (session *SessionConfig) block(blocked bool) {
if blocked == session.RunBlock && blocked == (session.ClearToLaunch != nil) {
// already configured
return
}
if blocked && session.Cmd.Process != nil {
log.Warnf("Refusing to block launched session: %s", session.ID)
return
}
if blocked {
log.Debugf("Blocking session launch: %s", session.ID)
session.RunBlock = true
session.ClearToLaunch = make(chan struct{})
return
}
// protect against multiple closes of the channel - the unblocker
// may not be able to take a session lock so cannot have that code clean
// up reliably
defer func() {
recover()
}()
log.Debugf("Unblocking session: %s", session.ID)
close(session.ClearToLaunch)
session.ClearToLaunch = nil
// reset Runblock to unblock process start next time
session.RunBlock = false
}
// Unblock takes a lock and constructs a function to call for releasing
// an explicit block. Does NOT take a session lock
func (session *SessionConfig) Unblock() func() {
launchChannel := session.ClearToLaunch
if !session.RunBlock || launchChannel == nil || session.Started != "" {
// if we're not in a blockable state return a no-op function
return func() {}
}
return func() {
session.once.Do(func() {
defer func() {
recover()
}()
log.Infof("Unblocking the launch of %s", session.ID)
// make sure that portlayer received the container id back - this will block
// in the write until the launch code is ready to consume the entry
launchChannel <- struct{}{}
log.Infof("Unblocked the launch of %s", session.ID)
})
}
}