Skip to content

Commit f0d8fe0

Browse files
committed
Implement secrets API
Signed-off-by: Joffrey F <[email protected]>
1 parent 4b636c3 commit f0d8fe0

File tree

4 files changed

+166
-0
lines changed

4 files changed

+166
-0
lines changed

docker/api/client.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from .image import ImageApiMixin
1616
from .network import NetworkApiMixin
1717
from .plugin import PluginApiMixin
18+
from .secret import SecretApiMixin
1819
from .service import ServiceApiMixin
1920
from .swarm import SwarmApiMixin
2021
from .volume import VolumeApiMixin
@@ -48,6 +49,7 @@ class APIClient(
4849
ImageApiMixin,
4950
NetworkApiMixin,
5051
PluginApiMixin,
52+
SecretApiMixin,
5153
ServiceApiMixin,
5254
SwarmApiMixin,
5355
VolumeApiMixin):

docker/api/secret.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import base64
2+
3+
from .. import utils
4+
5+
6+
class SecretApiMixin(object):
7+
@utils.minimum_version('1.25')
8+
def create_secret(self, name, data, labels=None):
9+
"""
10+
Create a secret
11+
12+
Args:
13+
name (string): Name of the secret
14+
data (bytes): Secret data to be stored
15+
labels (dict): A mapping of labels to assign to the secret
16+
17+
Returns (dict): ID of the newly created secret
18+
"""
19+
if not isinstance(data, bytes):
20+
data = data.encode('utf-8')
21+
22+
data = base64.b64encode(data)
23+
body = {
24+
'Data': data,
25+
'Name': name,
26+
'Labels': labels
27+
}
28+
29+
url = self._url('/secrets/create')
30+
return self._result(
31+
self._post_json(url, data=body), True
32+
)
33+
34+
@utils.minimum_version('1.25')
35+
@utils.check_resource
36+
def inspect_secret(self, id):
37+
"""
38+
Retrieve secret metadata
39+
40+
Args:
41+
id (string): Full ID of the secret to remove
42+
43+
Returns (dict): A dictionary of metadata
44+
45+
Raises:
46+
:py:class:`docker.errors.NotFound`
47+
if no secret with that ID exists
48+
"""
49+
url = self._url('/secrets/{0}', id)
50+
return self._result(self._get(url), True)
51+
52+
@utils.minimum_version('1.25')
53+
@utils.check_resource
54+
def remove_secret(self, id):
55+
"""
56+
Remove a secret
57+
58+
Args:
59+
id (string): Full ID of the secret to remove
60+
61+
Returns (boolean): True if successful
62+
63+
Raises:
64+
:py:class:`docker.errors.NotFound`
65+
if no secret with that ID exists
66+
"""
67+
url = self._url('/secrets/{0}', id)
68+
res = self._delete(url)
69+
self._raise_for_status(res)
70+
return True
71+
72+
@utils.minimum_version('1.25')
73+
def secrets(self, filters=None):
74+
"""
75+
List secrets
76+
77+
Args:
78+
filters (dict): A map of filters to process on the secrets
79+
list. Available filters: ``names``
80+
81+
Returns (list): A list of secrets
82+
"""
83+
url = self._url('/secrets')
84+
params = {}
85+
if filters:
86+
params['filters'] = utils.convert_filters(filters)
87+
return self._result(self._get(url, params=params), True)

docker/client.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from .models.networks import NetworkCollection
55
from .models.nodes import NodeCollection
66
from .models.plugins import PluginCollection
7+
from .models.secrets import SecretCollection
78
from .models.services import ServiceCollection
89
from .models.swarm import Swarm
910
from .models.volumes import VolumeCollection
@@ -118,6 +119,13 @@ def plugins(self):
118119
"""
119120
return PluginCollection(client=self)
120121

122+
def secrets(self):
123+
"""
124+
An object for managing secrets on the server. See the
125+
:doc:`secrets documentation <secrets>` for full details.
126+
"""
127+
return SecretCollection(client=self)
128+
121129
@property
122130
def services(self):
123131
"""

docker/models/secrets.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
from ..api import APIClient
2+
from .resource import Model, Collection
3+
4+
5+
class Secret(Model):
6+
"""A secret."""
7+
id_attribute = 'ID'
8+
9+
def __repr__(self):
10+
return "<%s: '%s'>" % (self.__class__.__name__, self.name)
11+
12+
@property
13+
def name(self):
14+
return self.attrs['Spec']['Name']
15+
16+
def remove(self):
17+
"""
18+
Remove this secret.
19+
20+
Raises:
21+
:py:class:`docker.errors.APIError`
22+
If secret failed to remove.
23+
"""
24+
return self.client.api.remove_secret(self.id)
25+
26+
27+
class SecretCollection(Collection):
28+
"""Secrets on the Docker server."""
29+
model = Secret
30+
31+
def create(self, **kwargs):
32+
obj = self.client.api.create_secret(**kwargs)
33+
return self.prepare_model(obj)
34+
create.__doc__ = APIClient.create_secret.__doc__
35+
36+
def get(self, secret_id):
37+
"""
38+
Get a secret.
39+
40+
Args:
41+
secret_id (str): Secret ID.
42+
43+
Returns:
44+
(:py:class:`Secret`): The secret.
45+
46+
Raises:
47+
:py:class:`docker.errors.NotFound`
48+
If the secret does not exist.
49+
:py:class:`docker.errors.APIError`
50+
If the server returns an error.
51+
"""
52+
return self.prepare_model(self.client.api.inspect_secret(secret_id))
53+
54+
def list(self, **kwargs):
55+
"""
56+
List secrets. Similar to the ``docker secret ls`` command.
57+
58+
Args:
59+
filters (dict): Server-side list filtering options.
60+
61+
Returns:
62+
(list of :py:class:`Secret`): The secrets.
63+
64+
Raises:
65+
:py:class:`docker.errors.APIError`
66+
If the server returns an error.
67+
"""
68+
resp = self.client.api.secrets(**kwargs)
69+
return [self.prepare_model(obj) for obj in resp]

0 commit comments

Comments
 (0)