-
Notifications
You must be signed in to change notification settings - Fork 20
/
volume.py
141 lines (107 loc) · 3.46 KB
/
volume.py
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
import manof
from twisted.internet import defer
class Volume(manof.Target):
def provision(self):
pass
def run(self):
pass
def stop(self):
pass
def rm(self):
pass
def lift(self):
pass
def exists(self):
pass
@property
def prefix(self):
return ""
@property
def volume_name(self):
return self.prefix + self.name
class NamedVolume(Volume):
def __init__(self, *args, **kwargs):
super(NamedVolume, self).__init__(*args, **kwargs)
self._lock = defer.DeferredLock()
@defer.inlineCallbacks
def provision(self, rm=None):
"""
De facto "docker volume create"
NOTE: docker volume creation is idempotent on data but repopulates labels
"""
if rm is None:
rm = "force_rm" in self._args and self._args.force_rm
if rm:
yield self.rm(safe=True)
self._logger.info("Creating named-volume", name=self.name)
creation_args = []
if len(self.labels):
for k, v in self.labels.items():
creation_args.append("--label {0}={1}".format(k, v))
if len(self.options):
for k, v in self.options.items():
creation_args.append("--opt {0}={1}".format(k, v))
command = "docker volume create {0} --driver={1} --name={2}".format(
" ".join(creation_args), self.driver, self.volume_name
)
# don't count on idempotency (labels):
exists = yield self.exists()
if exists:
self._logger.debug(
"Named volume exists. Doing nothing.", named_volume=self.volume_name
)
else:
self._logger.debug(
"Named volume doesn't exist. Creating.", named_volume=self.volume_name
)
yield self._run_command(command)
def run(self):
self._logger.info("Running a named-volume is meaningless", name=self.name)
def stop(self):
self._logger.info("Stopping a named-volume is meaningless", name=self.name)
@defer.inlineCallbacks
def rm(self, safe=True):
"""
De facto "docker volume rm"
"""
self._logger.info("Removing named-volume")
yield self._lock.acquire()
try:
if safe:
exists = yield self.exists()
if not exists:
defer.returnValue(None)
command = "docker volume rm {0}".format(self.volume_name)
# remove volume (fail if doesn't exist)
yield self._run_command(command)
finally:
self._lock.release()
@defer.inlineCallbacks
def lift(self):
self._logger.debug("Lifting")
# just provision
yield self.provision()
@defer.inlineCallbacks
def exists(self):
command = "docker volume inspect {0}".format(self.volume_name)
# retcode=0 -> volume exists
_, _, retcode = yield self._run_command(command, raise_on_error=False)
defer.returnValue(False if retcode else True)
@property
def prefix(self):
return ""
@property
def driver(self):
return "local"
@property
def options(self):
"""
Driver specific options, used on creation/provision
"""
return {}
@property
def labels(self):
"""
Will show as key=value when doing >>docker volume inspect <VOLUME_NAME>
"""
return {}