Passed
Push — master ( 71afca...9e5fe0 )
by Tom
04:18
created

AbstractionLayerImpl::exportTar()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 2
eloc 14
nc 2
nop 3
dl 0
loc 23
ccs 12
cts 12
cp 1
crap 2
rs 9.7998
c 1
b 0
f 1
1
<?php
2
3
/* this file is part of pipelines */
4
5
namespace Ktomk\Pipelines\Runner\Docker;
6
7
use Ktomk\Pipelines\Cli\Exec;
8
use Ktomk\Pipelines\Cli\ExecTester;
9
use Ktomk\Pipelines\Lib;
10
11
/**
12
 * Class DockerAbstractionLayer Implementation
13
 *
14
 * Implement all of the docker interaction (first of all from runners'
15
 * side) with the docker cli (the docker client binary) with a defined
16
 * interface. Any (new) interaction (inter!) with docker client
17
 * programmed against the interface so it can become part of the
18
 * runner component (for the interface) and inverse the dependency
19
 * against the hard working implementation.
20
 *
21
 * First implementation of the abstraction layer, as runner driven,
22
 * placed in there but perhaps must not belong into there but a
23
 * component of it's own (still exec driven, yet no passthru() in use,
24
 * hope to keep it, but it's a more leaking abstraction for pipelines,
25
 * so let's see how clean this can be done, in CLI context, passthru()
26
 * is especially useful for the overall pipelines utility, maybe when
27
 * breaking with it due to null-byte prevention leakage, see KNOWN BUGS)
28
 *
29
 * @package Ktomk\Pipelines\Runner\Docker
30
 */
31
class AbstractionLayerImpl implements AbstractionLayer
32
{
33
    /**
34
     * @var bool
35
     */
36
    private $throws;
37
38
    /**
39
     * @var Exec
40
     */
41
    private $exec;
42
43
    /**
44
     * DockerAbstractionLayer constructor.
45
     *
46
     * @param Exec $exec
47
     * @param bool $throws optional
48
     */
49 7
    public function __construct(Exec $exec, $throws = null)
50
    {
51 7
        $this->exec = $exec;
52 7
        $this->throws($throws);
53 7
    }
54
55 1
    public function execute($id, array $arguments)
56
    {
57 1
        $status = $this->exec->capture(
58 1
            $cmd = Lib::cmd(
59 1
                'docker',
60 1
                Lib::merge('exec', $id, $arguments)
61
            ),
62 1
            array(),
63
            $out,
64
            $err
65
        );
66
67 1
        if (0 !== $status) {
68 1
            $this->notifyNonZero($cmd, $status, $out, $err);
69
70 1
            return null;
71
        }
72
73 1
        return rtrim($out);
74
    }
75
76 1
    public function kill($idOrName)
77
    {
78 1
        $status = $this->exec->capture(
79 1
            $cmd = Lib::cmd(
80 1
                'docker',
81 1
                Lib::merge('kill', $idOrName)
82
            ),
83 1
            array(),
84
            $out,
85
            $err
86
        );
87
88 1
        if (0 !== $status) {
89 1
            $this->notifyNonZero($cmd, $status, $out, $err);
90
91 1
            return null;
92
        }
93
94 1
        return rtrim($out);
95
    }
96
97 1
    public function remove($idOrName, $force = true)
98
    {
99 1
        $status = $this->exec->capture(
100 1
            $cmd = Lib::cmd(
101 1
                'docker',
102 1
                Lib::merge('rm', $force ? '-f' : null, $idOrName)
103
            ),
104 1
            array(),
105
            $out,
106
            $err
107
        );
108
109 1
        if (1 === $status) {
110 1
            return null;
111
        }
112
113 1
        if (0 !== $status) {
114 1
            $this->notifyNonZero($cmd, $status, $out, $err);
115
116 1
            return null;
117
        }
118
119 1
        return rtrim($out);
120
    }
121
122 1
    public function start($image, array $arguments, array $runArguments = array())
123
    {
124 1
        $status = $this->exec->capture(
125 1
            $cmd = Lib::cmd(
126 1
                'docker',
127 1
                Lib::merge('run', array('--detach', '--entrypoint', '/bin/sh', '-it'), $arguments, $image, $runArguments)
128
            ),
129 1
            array(),
130
            $out,
131
            $err
132
        );
133
134 1
        if (0 !== $status) {
135 1
            $this->notifyNonZero($cmd, $status, $out, $err);
136
137 1
            return null;
138
        }
139
140 1
        return rtrim($out);
141
    }
142
143
    /* tar methods */
144
145 1
    public function importTar($tar, $id, $path)
146
    {
147 1
        $status = $this->exec->capture(
148 1
            $cmd = Lib::cmd(
149 1
                sprintf('<%s docker', Lib::quoteArg($tar)),
150
                array(
151 1
                    'cp',
152 1
                    '-',
153 1
                    sprintf('%s:%s', $id, $path),
154
                )
155
            ),
156 1
            array(),
157
            $out,
158
            $err
159
        );
160
161 1
        if (0 !== $status) {
162 1
            $this->notifyNonZero($cmd, $status, $out, $err);
163
164 1
            return null;
165
        }
166
167 1
        return true;
168
    }
169
170 1
    public function exportTar($id, $path, $tar)
171
    {
172 1
        $status = $this->exec->capture(
173 1
            $cmd = Lib::cmd(
174 1
                sprintf('>%s docker', Lib::quoteArg($tar)),
175
                array(
176 1
                    'cp',
177 1
                    sprintf('%s:%s', $id, $path),
178 1
                    '-',
179
                )
180
            ),
181 1
            array(),
182
            $out,
183
            $err
184
        );
185
186 1
        if (0 !== $status) {
187 1
            $this->notifyNonZero($cmd, $status, $out, $err);
188
189 1
            return null;
190
        }
191
192 1
        return $tar;
193
    }
194
195
    /* layer error/exception handling */
196
197 7
    public function throws($throws = null)
198
    {
199 7
        $this->throws = null === $throws
200 7
            ? $this->exec instanceof ExecTester
201 6
            : $throws;
202 7
    }
203
204
    /**
205
     * notify non zero status
206
     *
207
     * internal representation to throw, leaking as some non-zero values
208
     * for some of the abstractions are expected to simplify the interface
209
     * in which case the notification is not called.
210
     *
211
     * @param string $cmd
212
     * @param int $status
213
     * @param string $out
214
     * @param string $err
215
     */
216 6
    private function notifyNonZero($cmd, $status, $out, $err)
217
    {
218 6
        if (!$this->throws) {
219 6
            return;
220
        }
221
222 2
        throw new \RuntimeException(
223 2
            sprintf(
224 2
                "Failed to execute\n\n  %s\n\ngot status %d and error:\n\n  %s\n\nwith output:\n\n %s\n",
225
                $cmd,
226
                $status,
227
                $err,
228
                $out
229
            )
230
        );
231
    }
232
}
233