1// +build !dockerless
2
3/*
4Copyright 2015 The Kubernetes Authors.
5
6Licensed under the Apache License, Version 2.0 (the "License");
7you may not use this file except in compliance with the License.
8You may obtain a copy of the License at
9
10    http://www.apache.org/licenses/LICENSE-2.0
11
12Unless required by applicable law or agreed to in writing, software
13distributed under the License is distributed on an "AS IS" BASIS,
14WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15See the License for the specific language governing permissions and
16limitations under the License.
17*/
18
19package libdocker
20
21import (
22	"time"
23
24	dockertypes "github.com/docker/docker/api/types"
25	dockercontainer "github.com/docker/docker/api/types/container"
26	dockerimagetypes "github.com/docker/docker/api/types/image"
27
28	"k8s.io/kubernetes/pkg/kubelet/dockershim/metrics"
29)
30
31// instrumentedInterface wraps the Interface and records the operations
32// and errors metrics.
33type instrumentedInterface struct {
34	client Interface
35}
36
37// NewInstrumentedInterface creates an instrumented Interface from an existing Interface.
38func NewInstrumentedInterface(dockerClient Interface) Interface {
39	return instrumentedInterface{
40		client: dockerClient,
41	}
42}
43
44// recordOperation records the duration of the operation.
45func recordOperation(operation string, start time.Time) {
46	metrics.DockerOperations.WithLabelValues(operation).Inc()
47	metrics.DockerOperationsLatency.WithLabelValues(operation).Observe(metrics.SinceInSeconds(start))
48}
49
50// recordError records error for metric if an error occurred.
51func recordError(operation string, err error) {
52	if err != nil {
53		if _, ok := err.(operationTimeout); ok {
54			metrics.DockerOperationsTimeout.WithLabelValues(operation).Inc()
55		}
56		// Docker operation timeout error is also a docker error, so we don't add else here.
57		metrics.DockerOperationsErrors.WithLabelValues(operation).Inc()
58	}
59}
60
61func (in instrumentedInterface) ListContainers(options dockertypes.ContainerListOptions) ([]dockertypes.Container, error) {
62	const operation = "list_containers"
63	defer recordOperation(operation, time.Now())
64
65	out, err := in.client.ListContainers(options)
66	recordError(operation, err)
67	return out, err
68}
69
70func (in instrumentedInterface) InspectContainer(id string) (*dockertypes.ContainerJSON, error) {
71	const operation = "inspect_container"
72	defer recordOperation(operation, time.Now())
73
74	out, err := in.client.InspectContainer(id)
75	recordError(operation, err)
76	return out, err
77}
78
79func (in instrumentedInterface) InspectContainerWithSize(id string) (*dockertypes.ContainerJSON, error) {
80	const operation = "inspect_container_withsize"
81	defer recordOperation(operation, time.Now())
82
83	out, err := in.client.InspectContainerWithSize(id)
84	recordError(operation, err)
85	return out, err
86}
87
88func (in instrumentedInterface) CreateContainer(opts dockertypes.ContainerCreateConfig) (*dockercontainer.ContainerCreateCreatedBody, error) {
89	const operation = "create_container"
90	defer recordOperation(operation, time.Now())
91
92	out, err := in.client.CreateContainer(opts)
93	recordError(operation, err)
94	return out, err
95}
96
97func (in instrumentedInterface) StartContainer(id string) error {
98	const operation = "start_container"
99	defer recordOperation(operation, time.Now())
100
101	err := in.client.StartContainer(id)
102	recordError(operation, err)
103	return err
104}
105
106func (in instrumentedInterface) StopContainer(id string, timeout time.Duration) error {
107	const operation = "stop_container"
108	defer recordOperation(operation, time.Now())
109
110	err := in.client.StopContainer(id, timeout)
111	recordError(operation, err)
112	return err
113}
114
115func (in instrumentedInterface) RemoveContainer(id string, opts dockertypes.ContainerRemoveOptions) error {
116	const operation = "remove_container"
117	defer recordOperation(operation, time.Now())
118
119	err := in.client.RemoveContainer(id, opts)
120	recordError(operation, err)
121	return err
122}
123
124func (in instrumentedInterface) UpdateContainerResources(id string, updateConfig dockercontainer.UpdateConfig) error {
125	const operation = "update_container"
126	defer recordOperation(operation, time.Now())
127
128	err := in.client.UpdateContainerResources(id, updateConfig)
129	recordError(operation, err)
130	return err
131}
132
133func (in instrumentedInterface) InspectImageByRef(image string) (*dockertypes.ImageInspect, error) {
134	const operation = "inspect_image"
135	defer recordOperation(operation, time.Now())
136
137	out, err := in.client.InspectImageByRef(image)
138	recordError(operation, err)
139	return out, err
140}
141
142func (in instrumentedInterface) InspectImageByID(image string) (*dockertypes.ImageInspect, error) {
143	const operation = "inspect_image"
144	defer recordOperation(operation, time.Now())
145
146	out, err := in.client.InspectImageByID(image)
147	recordError(operation, err)
148	return out, err
149}
150
151func (in instrumentedInterface) ListImages(opts dockertypes.ImageListOptions) ([]dockertypes.ImageSummary, error) {
152	const operation = "list_images"
153	defer recordOperation(operation, time.Now())
154
155	out, err := in.client.ListImages(opts)
156	recordError(operation, err)
157	return out, err
158}
159
160func (in instrumentedInterface) PullImage(imageID string, auth dockertypes.AuthConfig, opts dockertypes.ImagePullOptions) error {
161	const operation = "pull_image"
162	defer recordOperation(operation, time.Now())
163	err := in.client.PullImage(imageID, auth, opts)
164	recordError(operation, err)
165	return err
166}
167
168func (in instrumentedInterface) RemoveImage(image string, opts dockertypes.ImageRemoveOptions) ([]dockertypes.ImageDeleteResponseItem, error) {
169	const operation = "remove_image"
170	defer recordOperation(operation, time.Now())
171
172	imageDelete, err := in.client.RemoveImage(image, opts)
173	recordError(operation, err)
174	return imageDelete, err
175}
176
177func (in instrumentedInterface) Logs(id string, opts dockertypes.ContainerLogsOptions, sopts StreamOptions) error {
178	const operation = "logs"
179	defer recordOperation(operation, time.Now())
180
181	err := in.client.Logs(id, opts, sopts)
182	recordError(operation, err)
183	return err
184}
185
186func (in instrumentedInterface) Version() (*dockertypes.Version, error) {
187	const operation = "version"
188	defer recordOperation(operation, time.Now())
189
190	out, err := in.client.Version()
191	recordError(operation, err)
192	return out, err
193}
194
195func (in instrumentedInterface) Info() (*dockertypes.Info, error) {
196	const operation = "info"
197	defer recordOperation(operation, time.Now())
198
199	out, err := in.client.Info()
200	recordError(operation, err)
201	return out, err
202}
203
204func (in instrumentedInterface) CreateExec(id string, opts dockertypes.ExecConfig) (*dockertypes.IDResponse, error) {
205	const operation = "create_exec"
206	defer recordOperation(operation, time.Now())
207
208	out, err := in.client.CreateExec(id, opts)
209	recordError(operation, err)
210	return out, err
211}
212
213func (in instrumentedInterface) StartExec(startExec string, opts dockertypes.ExecStartCheck, sopts StreamOptions) error {
214	const operation = "start_exec"
215	defer recordOperation(operation, time.Now())
216
217	err := in.client.StartExec(startExec, opts, sopts)
218	recordError(operation, err)
219	return err
220}
221
222func (in instrumentedInterface) InspectExec(id string) (*dockertypes.ContainerExecInspect, error) {
223	const operation = "inspect_exec"
224	defer recordOperation(operation, time.Now())
225
226	out, err := in.client.InspectExec(id)
227	recordError(operation, err)
228	return out, err
229}
230
231func (in instrumentedInterface) AttachToContainer(id string, opts dockertypes.ContainerAttachOptions, sopts StreamOptions) error {
232	const operation = "attach"
233	defer recordOperation(operation, time.Now())
234
235	err := in.client.AttachToContainer(id, opts, sopts)
236	recordError(operation, err)
237	return err
238}
239
240func (in instrumentedInterface) ImageHistory(id string) ([]dockerimagetypes.HistoryResponseItem, error) {
241	const operation = "image_history"
242	defer recordOperation(operation, time.Now())
243
244	out, err := in.client.ImageHistory(id)
245	recordError(operation, err)
246	return out, err
247}
248
249func (in instrumentedInterface) ResizeExecTTY(id string, height, width uint) error {
250	const operation = "resize_exec"
251	defer recordOperation(operation, time.Now())
252
253	err := in.client.ResizeExecTTY(id, height, width)
254	recordError(operation, err)
255	return err
256}
257
258func (in instrumentedInterface) ResizeContainerTTY(id string, height, width uint) error {
259	const operation = "resize_container"
260	defer recordOperation(operation, time.Now())
261
262	err := in.client.ResizeContainerTTY(id, height, width)
263	recordError(operation, err)
264	return err
265}
266
267func (in instrumentedInterface) GetContainerStats(id string) (*dockertypes.StatsJSON, error) {
268	const operation = "stats"
269	defer recordOperation(operation, time.Now())
270
271	out, err := in.client.GetContainerStats(id)
272	recordError(operation, err)
273	return out, err
274}
275