podman
461 строка · 14.6 Кб
1// Copyright 2018 go-dockerclient authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package docker
6
7import (
8"context"
9"encoding/json"
10"errors"
11"io"
12"net/http"
13)
14
15// PluginPrivilege represents a privilege for a plugin.
16type PluginPrivilege struct {
17Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"`
18Description string `json:"Description,omitempty" yaml:"Description,omitempty" toml:"Description,omitempty"`
19Value []string `json:"Value,omitempty" yaml:"Value,omitempty" toml:"Value,omitempty"`
20}
21
22// InstallPluginOptions specify parameters to the InstallPlugins function.
23//
24// See https://goo.gl/C4t7Tz for more details.
25type InstallPluginOptions struct {
26Remote string
27Name string
28Plugins []PluginPrivilege `qs:"-"`
29
30Auth AuthConfiguration
31
32Context context.Context
33}
34
35// InstallPlugins installs a plugin or returns an error in case of failure.
36//
37// See https://goo.gl/C4t7Tz for more details.
38func (c *Client) InstallPlugins(opts InstallPluginOptions) error {
39headers, err := headersWithAuth(opts.Auth)
40if err != nil {
41return err
42}
43
44path := "/plugins/pull?" + queryString(opts)
45resp, err := c.do(http.MethodPost, path, doOptions{
46data: opts.Plugins,
47context: opts.Context,
48headers: headers,
49})
50if err != nil {
51return err
52}
53defer resp.Body.Close()
54// PullPlugin streams back the progress of the pull, we must consume the whole body
55// otherwise the pull will be canceled on the engine.
56if _, err := io.ReadAll(resp.Body); err != nil {
57return err
58}
59return nil
60}
61
62// PluginSettings stores plugin settings.
63//
64// See https://goo.gl/C4t7Tz for more details.
65type PluginSettings struct {
66Env []string `json:"Env,omitempty" yaml:"Env,omitempty" toml:"Env,omitempty"`
67Args []string `json:"Args,omitempty" yaml:"Args,omitempty" toml:"Args,omitempty"`
68Devices []string `json:"Devices,omitempty" yaml:"Devices,omitempty" toml:"Devices,omitempty"`
69}
70
71// PluginInterface stores plugin interface.
72//
73// See https://goo.gl/C4t7Tz for more details.
74type PluginInterface struct {
75Types []string `json:"Types,omitempty" yaml:"Types,omitempty" toml:"Types,omitempty"`
76Socket string `json:"Socket,omitempty" yaml:"Socket,omitempty" toml:"Socket,omitempty"`
77}
78
79// PluginNetwork stores plugin network type.
80//
81// See https://goo.gl/C4t7Tz for more details.
82type PluginNetwork struct {
83Type string `json:"Type,omitempty" yaml:"Type,omitempty" toml:"Type,omitempty"`
84}
85
86// PluginLinux stores plugin linux setting.
87//
88// See https://goo.gl/C4t7Tz for more details.
89type PluginLinux struct {
90Capabilities []string `json:"Capabilities,omitempty" yaml:"Capabilities,omitempty" toml:"Capabilities,omitempty"`
91AllowAllDevices bool `json:"AllowAllDevices,omitempty" yaml:"AllowAllDevices,omitempty" toml:"AllowAllDevices,omitempty"`
92Devices []PluginLinuxDevices `json:"Devices,omitempty" yaml:"Devices,omitempty" toml:"Devices,omitempty"`
93}
94
95// PluginLinuxDevices stores plugin linux device setting.
96//
97// See https://goo.gl/C4t7Tz for more details.
98type PluginLinuxDevices struct {
99Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"`
100Description string `json:"Documentation,omitempty" yaml:"Documentation,omitempty" toml:"Documentation,omitempty"`
101Settable []string `json:"Settable,omitempty" yaml:"Settable,omitempty" toml:"Settable,omitempty"`
102Path string `json:"Path,omitempty" yaml:"Path,omitempty" toml:"Path,omitempty"`
103}
104
105// PluginEnv stores plugin environment.
106//
107// See https://goo.gl/C4t7Tz for more details.
108type PluginEnv struct {
109Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"`
110Description string `json:"Description,omitempty" yaml:"Description,omitempty" toml:"Description,omitempty"`
111Settable []string `json:"Settable,omitempty" yaml:"Settable,omitempty" toml:"Settable,omitempty"`
112Value string `json:"Value,omitempty" yaml:"Value,omitempty" toml:"Value,omitempty"`
113}
114
115// PluginArgs stores plugin arguments.
116//
117// See https://goo.gl/C4t7Tz for more details.
118type PluginArgs struct {
119Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"`
120Description string `json:"Description,omitempty" yaml:"Description,omitempty" toml:"Description,omitempty"`
121Settable []string `json:"Settable,omitempty" yaml:"Settable,omitempty" toml:"Settable,omitempty"`
122Value []string `json:"Value,omitempty" yaml:"Value,omitempty" toml:"Value,omitempty"`
123}
124
125// PluginUser stores plugin user.
126//
127// See https://goo.gl/C4t7Tz for more details.
128type PluginUser struct {
129UID int32 `json:"UID,omitempty" yaml:"UID,omitempty" toml:"UID,omitempty"`
130GID int32 `json:"GID,omitempty" yaml:"GID,omitempty" toml:"GID,omitempty"`
131}
132
133// PluginConfig stores plugin config.
134//
135// See https://goo.gl/C4t7Tz for more details.
136type PluginConfig struct {
137Description string `json:"Description,omitempty" yaml:"Description,omitempty" toml:"Description,omitempty"`
138Documentation string
139Interface PluginInterface `json:"Interface,omitempty" yaml:"Interface,omitempty" toml:"Interface,omitempty"`
140Entrypoint []string `json:"Entrypoint,omitempty" yaml:"Entrypoint,omitempty" toml:"Entrypoint,omitempty"`
141WorkDir string `json:"WorkDir,omitempty" yaml:"WorkDir,omitempty" toml:"WorkDir,omitempty"`
142User PluginUser `json:"User,omitempty" yaml:"User,omitempty" toml:"User,omitempty"`
143Network PluginNetwork `json:"Network,omitempty" yaml:"Network,omitempty" toml:"Network,omitempty"`
144Linux PluginLinux `json:"Linux,omitempty" yaml:"Linux,omitempty" toml:"Linux,omitempty"`
145PropagatedMount string `json:"PropagatedMount,omitempty" yaml:"PropagatedMount,omitempty" toml:"PropagatedMount,omitempty"`
146Mounts []Mount `json:"Mounts,omitempty" yaml:"Mounts,omitempty" toml:"Mounts,omitempty"`
147Env []PluginEnv `json:"Env,omitempty" yaml:"Env,omitempty" toml:"Env,omitempty"`
148Args PluginArgs `json:"Args,omitempty" yaml:"Args,omitempty" toml:"Args,omitempty"`
149}
150
151// PluginDetail specify results from the ListPlugins function.
152//
153// See https://goo.gl/C4t7Tz for more details.
154type PluginDetail struct {
155ID string `json:"Id,omitempty" yaml:"Id,omitempty" toml:"Id,omitempty"`
156Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"`
157Tag string `json:"Tag,omitempty" yaml:"Tag,omitempty" toml:"Tag,omitempty"`
158Active bool `json:"Enabled,omitempty" yaml:"Active,omitempty" toml:"Active,omitempty"`
159Settings PluginSettings `json:"Settings,omitempty" yaml:"Settings,omitempty" toml:"Settings,omitempty"`
160Config PluginConfig `json:"Config,omitempty" yaml:"Config,omitempty" toml:"Config,omitempty"`
161}
162
163// ListPlugins returns pluginDetails or an error.
164//
165// See https://goo.gl/C4t7Tz for more details.
166func (c *Client) ListPlugins(ctx context.Context) ([]PluginDetail, error) {
167resp, err := c.do(http.MethodGet, "/plugins", doOptions{
168context: ctx,
169})
170if err != nil {
171return nil, err
172}
173defer resp.Body.Close()
174pluginDetails := make([]PluginDetail, 0)
175if err := json.NewDecoder(resp.Body).Decode(&pluginDetails); err != nil {
176return nil, err
177}
178return pluginDetails, nil
179}
180
181// ListFilteredPluginsOptions specify parameters to the ListFilteredPlugins function.
182//
183// See https://goo.gl/C4t7Tz for more details.
184type ListFilteredPluginsOptions struct {
185Filters map[string][]string
186Context context.Context
187}
188
189// ListFilteredPlugins returns pluginDetails or an error.
190//
191// See https://goo.gl/rmdmWg for more details.
192func (c *Client) ListFilteredPlugins(opts ListFilteredPluginsOptions) ([]PluginDetail, error) {
193path := "/plugins/json?" + queryString(opts)
194resp, err := c.do(http.MethodGet, path, doOptions{
195context: opts.Context,
196})
197if err != nil {
198return nil, err
199}
200defer resp.Body.Close()
201pluginDetails := make([]PluginDetail, 0)
202if err := json.NewDecoder(resp.Body).Decode(&pluginDetails); err != nil {
203return nil, err
204}
205return pluginDetails, nil
206}
207
208// GetPluginPrivileges returns pluginPrivileges or an error.
209//
210// See https://goo.gl/C4t7Tz for more details.
211func (c *Client) GetPluginPrivileges(remote string, ctx context.Context) ([]PluginPrivilege, error) {
212return c.GetPluginPrivilegesWithOptions(
213GetPluginPrivilegesOptions{
214Remote: remote,
215Context: ctx,
216})
217}
218
219// GetPluginPrivilegesOptions specify parameters to the GetPluginPrivilegesWithOptions function.
220//
221// See https://goo.gl/C4t7Tz for more details.
222type GetPluginPrivilegesOptions struct {
223Remote string
224Auth AuthConfiguration
225Context context.Context
226}
227
228// GetPluginPrivilegesWithOptions returns pluginPrivileges or an error.
229//
230// See https://goo.gl/C4t7Tz for more details.
231func (c *Client) GetPluginPrivilegesWithOptions(opts GetPluginPrivilegesOptions) ([]PluginPrivilege, error) {
232headers, err := headersWithAuth(opts.Auth)
233if err != nil {
234return nil, err
235}
236
237path := "/plugins/privileges?" + queryString(opts)
238resp, err := c.do(http.MethodGet, path, doOptions{
239context: opts.Context,
240headers: headers,
241})
242if err != nil {
243return nil, err
244}
245defer resp.Body.Close()
246var pluginPrivileges []PluginPrivilege
247if err := json.NewDecoder(resp.Body).Decode(&pluginPrivileges); err != nil {
248return nil, err
249}
250return pluginPrivileges, nil
251}
252
253// InspectPlugins returns a pluginDetail or an error.
254//
255// See https://goo.gl/C4t7Tz for more details.
256func (c *Client) InspectPlugins(name string, ctx context.Context) (*PluginDetail, error) {
257resp, err := c.do(http.MethodGet, "/plugins/"+name+"/json", doOptions{
258context: ctx,
259})
260if err != nil {
261var e *Error
262if errors.As(err, &e) && e.Status == http.StatusNotFound {
263return nil, &NoSuchPlugin{ID: name}
264}
265return nil, err
266}
267defer resp.Body.Close()
268var pluginDetail PluginDetail
269if err := json.NewDecoder(resp.Body).Decode(&pluginDetail); err != nil {
270return nil, err
271}
272return &pluginDetail, nil
273}
274
275// RemovePluginOptions specify parameters to the RemovePlugin function.
276//
277// See https://goo.gl/C4t7Tz for more details.
278type RemovePluginOptions struct {
279// The Name of the plugin.
280Name string `qs:"-"`
281
282Force bool `qs:"force"`
283Context context.Context
284}
285
286// RemovePlugin returns a PluginDetail or an error.
287//
288// See https://goo.gl/C4t7Tz for more details.
289func (c *Client) RemovePlugin(opts RemovePluginOptions) (*PluginDetail, error) {
290path := "/plugins/" + opts.Name + "?" + queryString(opts)
291resp, err := c.do(http.MethodDelete, path, doOptions{context: opts.Context})
292if err != nil {
293var e *Error
294if errors.As(err, &e) && e.Status == http.StatusNotFound {
295return nil, &NoSuchPlugin{ID: opts.Name}
296}
297return nil, err
298}
299defer resp.Body.Close()
300body, err := io.ReadAll(resp.Body)
301if err != nil {
302return nil, err
303}
304
305if len(body) == 0 {
306// Seems like newer docker versions won't return the plugindetail after removal
307return nil, nil
308}
309
310var pluginDetail PluginDetail
311if err := json.Unmarshal(body, &pluginDetail); err != nil {
312return nil, err
313}
314return &pluginDetail, nil
315}
316
317// EnablePluginOptions specify parameters to the EnablePlugin function.
318//
319// See https://goo.gl/C4t7Tz for more details.
320type EnablePluginOptions struct {
321// The Name of the plugin.
322Name string `qs:"-"`
323Timeout int64 `qs:"timeout"`
324
325Context context.Context
326}
327
328// EnablePlugin enables plugin that opts point or returns an error.
329//
330// See https://goo.gl/C4t7Tz for more details.
331func (c *Client) EnablePlugin(opts EnablePluginOptions) error {
332path := "/plugins/" + opts.Name + "/enable?" + queryString(opts)
333resp, err := c.do(http.MethodPost, path, doOptions{context: opts.Context})
334if err != nil {
335return err
336}
337resp.Body.Close()
338return nil
339}
340
341// DisablePluginOptions specify parameters to the DisablePlugin function.
342//
343// See https://goo.gl/C4t7Tz for more details.
344type DisablePluginOptions struct {
345// The Name of the plugin.
346Name string `qs:"-"`
347
348Context context.Context
349}
350
351// DisablePlugin disables plugin that opts point or returns an error.
352//
353// See https://goo.gl/C4t7Tz for more details.
354func (c *Client) DisablePlugin(opts DisablePluginOptions) error {
355path := "/plugins/" + opts.Name + "/disable"
356resp, err := c.do(http.MethodPost, path, doOptions{context: opts.Context})
357if err != nil {
358return err
359}
360resp.Body.Close()
361return nil
362}
363
364// CreatePluginOptions specify parameters to the CreatePlugin function.
365//
366// See https://goo.gl/C4t7Tz for more details.
367type CreatePluginOptions struct {
368// The Name of the plugin.
369Name string `qs:"name"`
370// Path to tar containing plugin
371Path string `qs:"-"`
372
373Context context.Context
374}
375
376// CreatePlugin creates plugin that opts point or returns an error.
377//
378// See https://goo.gl/C4t7Tz for more details.
379func (c *Client) CreatePlugin(opts CreatePluginOptions) (string, error) {
380path := "/plugins/create?" + queryString(opts)
381resp, err := c.do(http.MethodPost, path, doOptions{
382data: opts.Path,
383context: opts.Context,
384})
385if err != nil {
386return "", err
387}
388defer resp.Body.Close()
389containerNameBytes, err := io.ReadAll(resp.Body)
390if err != nil {
391return "", err
392}
393return string(containerNameBytes), nil
394}
395
396// PushPluginOptions specify parameters to PushPlugin function.
397//
398// See https://goo.gl/C4t7Tz for more details.
399type PushPluginOptions struct {
400// The Name of the plugin.
401Name string
402
403Context context.Context
404}
405
406// PushPlugin pushes plugin that opts point or returns an error.
407//
408// See https://goo.gl/C4t7Tz for more details.
409func (c *Client) PushPlugin(opts PushPluginOptions) error {
410path := "/plugins/" + opts.Name + "/push"
411resp, err := c.do(http.MethodPost, path, doOptions{context: opts.Context})
412if err != nil {
413return err
414}
415resp.Body.Close()
416return nil
417}
418
419// ConfigurePluginOptions specify parameters to the ConfigurePlugin
420//
421// See https://goo.gl/C4t7Tz for more details.
422type ConfigurePluginOptions struct {
423// The Name of the plugin.
424Name string `qs:"name"`
425Envs []string
426
427Context context.Context
428}
429
430// ConfigurePlugin configures plugin that opts point or returns an error.
431//
432// See https://goo.gl/C4t7Tz for more details.
433func (c *Client) ConfigurePlugin(opts ConfigurePluginOptions) error {
434path := "/plugins/" + opts.Name + "/set"
435resp, err := c.do(http.MethodPost, path, doOptions{
436data: opts.Envs,
437context: opts.Context,
438})
439if err != nil {
440var e *Error
441if errors.As(err, &e) && e.Status == http.StatusNotFound {
442return &NoSuchPlugin{ID: opts.Name}
443}
444return err
445}
446resp.Body.Close()
447return nil
448}
449
450// NoSuchPlugin is the error returned when a given plugin does not exist.
451type NoSuchPlugin struct {
452ID string
453Err error
454}
455
456func (err *NoSuchPlugin) Error() string {
457if err.Err != nil {
458return err.Err.Error()
459}
460return "No such plugin: " + err.ID
461}
462