forked from google/cadvisor
-
Notifications
You must be signed in to change notification settings - Fork 0
/
compatibility.go
275 lines (228 loc) · 9.98 KB
/
compatibility.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
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
// Copyright 2015 Google 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 libcontainer
import (
"encoding/json"
"io/ioutil"
"path"
"github.com/docker/libcontainer"
"github.com/docker/libcontainer/configs"
"github.com/google/cadvisor/utils"
)
// State represents a running container's state
type preAPIState struct {
// InitPid is the init process id in the parent namespace
InitPid int `json:"init_pid,omitempty"`
// InitStartTime is the init process start time
InitStartTime string `json:"init_start_time,omitempty"`
// Network runtime state.
NetworkState preAPINetworkState `json:"network_state,omitempty"`
// Path to all the cgroups setup for a container. Key is cgroup subsystem name.
CgroupPaths map[string]string `json:"cgroup_paths,omitempty"`
}
// Struct describing the network specific runtime state that will be maintained by libcontainer for all running containers
// Do not depend on it outside of libcontainer.
type preAPINetworkState struct {
// The name of the veth interface on the Host.
VethHost string `json:"veth_host,omitempty"`
// The name of the veth interface created inside the container for the child.
VethChild string `json:"veth_child,omitempty"`
// Net namespace path.
NsPath string `json:"ns_path,omitempty"`
}
type preAPIConfig struct {
// Pathname to container's root filesystem
RootFs string `json:"root_fs,omitempty"`
// Hostname optionally sets the container's hostname if provided
Hostname string `json:"hostname,omitempty"`
// User will set the uid and gid of the executing process running inside the container
User string `json:"user,omitempty"`
// WorkingDir will change the processes current working directory inside the container's rootfs
WorkingDir string `json:"working_dir,omitempty"`
// Env will populate the processes environment with the provided values
// Any values from the parent processes will be cleared before the values
// provided in Env are provided to the process
Env []string `json:"environment,omitempty"`
// Tty when true will allocate a pty slave on the host for access by the container's process
// and ensure that it is mounted inside the container's rootfs
Tty bool `json:"tty,omitempty"`
// Namespaces specifies the container's namespaces that it should setup when cloning the init process
// If a namespace is not provided that namespace is shared from the container's parent process
Namespaces []configs.Namespace `json:"namespaces,omitempty"`
// Capabilities specify the capabilities to keep when executing the process inside the container
// All capbilities not specified will be dropped from the processes capability mask
Capabilities []string `json:"capabilities,omitempty"`
// Networks specifies the container's network setup to be created
Networks []preAPINetwork `json:"networks,omitempty"`
// Routes can be specified to create entries in the route table as the container is started
Routes []*configs.Route `json:"routes,omitempty"`
// Cgroups specifies specific cgroup settings for the various subsystems that the container is
// placed into to limit the resources the container has available
Cgroups *configs.Cgroup `json:"cgroups,omitempty"`
// AppArmorProfile specifies the profile to apply to the process running in the container and is
// change at the time the process is execed
AppArmorProfile string `json:"apparmor_profile,omitempty"`
// ProcessLabel specifies the label to apply to the process running in the container. It is
// commonly used by selinux
ProcessLabel string `json:"process_label,omitempty"`
// RestrictSys will remount /proc/sys, /sys, and mask over sysrq-trigger as well as /proc/irq and
// /proc/bus
RestrictSys bool `json:"restrict_sys,omitempty"`
}
// Network defines configuration for a container's networking stack
//
// The network configuration can be omited from a container causing the
// container to be setup with the host's networking stack
type preAPINetwork struct {
// Type sets the networks type, commonly veth and loopback
Type string `json:"type,omitempty"`
// The bridge to use.
Bridge string `json:"bridge,omitempty"`
// Prefix for the veth interfaces.
VethPrefix string `json:"veth_prefix,omitempty"`
// MacAddress contains the MAC address to set on the network interface
MacAddress string `json:"mac_address,omitempty"`
// Address contains the IPv4 and mask to set on the network interface
Address string `json:"address,omitempty"`
// IPv6Address contains the IPv6 and mask to set on the network interface
IPv6Address string `json:"ipv6_address,omitempty"`
// Gateway sets the gateway address that is used as the default for the interface
Gateway string `json:"gateway,omitempty"`
// IPv6Gateway sets the ipv6 gateway address that is used as the default for the interface
IPv6Gateway string `json:"ipv6_gateway,omitempty"`
// Mtu sets the mtu value for the interface and will be mirrored on both the host and
// container's interfaces if a pair is created, specifically in the case of type veth
// Note: This does not apply to loopback interfaces.
Mtu int `json:"mtu,omitempty"`
// TxQueueLen sets the tx_queuelen value for the interface and will be mirrored on both the host and
// container's interfaces if a pair is created, specifically in the case of type veth
// Note: This does not apply to loopback interfaces.
TxQueueLen int `json:"txqueuelen,omitempty"`
}
// Relative path to the libcontainer execdriver directory.
const libcontainerExecDriverPath = "execdriver/native"
// TODO(vmarmol): Deprecate over time as old Dockers are phased out.
func ReadConfig(dockerRoot, dockerRun, containerID string) (*configs.Config, error) {
// Try using the new config if it is available.
configPath := configPath(dockerRun, containerID)
if utils.FileExists(configPath) {
out, err := ioutil.ReadFile(configPath)
if err != nil {
return nil, err
}
var state libcontainer.State
err = json.Unmarshal(out, &state)
if err != nil {
return nil, err
}
return &state.Config, nil
}
// Fallback to reading the old config which is comprised of the state and config files.
oldConfigPath := oldConfigPath(dockerRoot, containerID)
out, err := ioutil.ReadFile(oldConfigPath)
if err != nil {
return nil, err
}
// Try reading the preAPIConfig.
var config preAPIConfig
err = json.Unmarshal(out, &config)
if err != nil {
// Try to parse the old pre-API config. The main difference is that namespaces used to be a map, now it is a slice of structs.
// The JSON marshaler will use the non-nested field before the nested one.
type oldLibcontainerConfig struct {
preAPIConfig
OldNamespaces map[string]bool `json:"namespaces,omitempty"`
}
var oldConfig oldLibcontainerConfig
err2 := json.Unmarshal(out, &oldConfig)
if err2 != nil {
// Use original error.
return nil, err
}
// Translate the old pre-API config into the new config.
config = oldConfig.preAPIConfig
for ns := range oldConfig.OldNamespaces {
config.Namespaces = append(config.Namespaces, configs.Namespace{
Type: configs.NamespaceType(ns),
})
}
}
// Read the old state file as well.
state, err := readState(dockerRoot, containerID)
if err != nil {
return nil, err
}
// Convert preAPIConfig + old state file to Config.
// This only converts some of the fields, the ones we use.
// You may need to add fields if the one you're interested in is not available.
var result configs.Config
result.Cgroups = new(configs.Cgroup)
result.Rootfs = config.RootFs
result.Hostname = config.Hostname
result.Namespaces = config.Namespaces
result.Capabilities = config.Capabilities
for _, net := range config.Networks {
n := &configs.Network{
Name: state.NetworkState.VethChild,
Bridge: net.Bridge,
MacAddress: net.MacAddress,
Address: net.Address,
Gateway: net.Gateway,
IPv6Address: net.IPv6Address,
IPv6Gateway: net.IPv6Gateway,
HostInterfaceName: state.NetworkState.VethHost,
}
result.Networks = append(result.Networks, n)
}
result.Routes = config.Routes
if config.Cgroups != nil {
result.Cgroups = config.Cgroups
}
return &result, nil
}
func readState(dockerRoot, containerID string) (preAPIState, error) {
// pre-API libcontainer changed how its state was stored, try the old way of a "pid" file
statePath := path.Join(dockerRoot, libcontainerExecDriverPath, containerID, "state.json")
if !utils.FileExists(statePath) {
pidPath := path.Join(dockerRoot, libcontainerExecDriverPath, containerID, "pid")
if utils.FileExists(pidPath) {
// We don't need the old state, return an empty state and we'll gracefully degrade.
return preAPIState{}, nil
}
}
out, err := ioutil.ReadFile(statePath)
if err != nil {
return preAPIState{}, err
}
// Parse the state.
var state preAPIState
err = json.Unmarshal(out, &state)
if err != nil {
return preAPIState{}, err
}
return state, nil
}
// Gets the path to the libcontainer configuration.
func configPath(dockerRun, containerID string) string {
return path.Join(dockerRun, libcontainerExecDriverPath, containerID, "state.json")
}
// Gets the path to the old libcontainer configuration.
func oldConfigPath(dockerRoot, containerID string) string {
return path.Join(dockerRoot, libcontainerExecDriverPath, containerID, "container.json")
}
// Gets whether the specified container exists.
func Exists(dockerRoot, dockerRun, containerID string) bool {
// New or old config must exist for the container to be considered alive.
return utils.FileExists(configPath(dockerRun, containerID)) || utils.FileExists(oldConfigPath(dockerRoot, containerID))
}