Skip to content
This repository was archived by the owner on Nov 19, 2024. It is now read-only.

Commit 6af5f81

Browse files
author
Sven Speckmaier
authored
Merge pull request #2 from ipunkt/cron
Cron
2 parents d3d085a + 4f829c0 commit 6af5f81

File tree

4 files changed

+281
-12
lines changed

4 files changed

+281
-12
lines changed

README.md

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,80 @@
1-
# rancherize-blueprint-php-cli
1+
# rancherize-blueprint-php-cli
2+
Rancherize blueprint to run a single php command, optionally with cron label to run regularly.
3+
4+
## Use
5+
6+
### Install
7+
8+
rancherize plugin:install ipunkt/rancherize-blueprint-php-cli:1.0.0
9+
10+
### Init
11+
Init local development environment
12+
13+
rancherize init php-cli --dev local
14+
15+
Init push environment to be used with a rancher server
16+
17+
rancherize init php-cli production
18+
19+
Note that as of the time of writing all environments will use the same blueprint
20+
21+
### Configuration
22+
23+
#### Differences from WebserverBlueprint
24+
- `command`: The command that will be executed. The exact command that will be run is `php VALUEGIVEN` inside `/var/cli/app` where your app is mounted.
25+
- `add-composer`: Add a composer.phar to your app directory
26+
27+
#### Supported rancherize services
28+
- [scheduler](https://github.com/ipunkt/rancherize/tree/master/app/Blueprint/Scheduler)
29+
- Cron [schedule](https://github.com/ipunkt/rancherize/tree/master/app/Blueprint/Cron) IMPORTANT: Not the full `cron` syntax is supported. Only the `schedule` part is used on the top level of the environment
30+
31+
#### Example:
32+
```json
33+
{
34+
"default": {
35+
"rancher": {
36+
"account": "accountname",
37+
"in-service": true
38+
},
39+
"docker": {
40+
"account": "accountname",
41+
"repository": "dockername\/reponame",
42+
"version-prefix": "cli_test_",
43+
"base-image": "php:7.0-alpine"
44+
},
45+
"service-name": "ServiceName",
46+
"php": "7.0",
47+
"add-composer": false,
48+
"command": "artisan",
49+
"schedule":{
50+
"hour":"*/2"
51+
},
52+
"scheduler": {
53+
"enable": true
54+
}
55+
},
56+
"environments": {
57+
"local": {
58+
"mount-workdir": true,
59+
"external_links": [],
60+
"environment": {
61+
"EXAMPLE": "value"
62+
}
63+
},
64+
"staging": {
65+
"rancher": {
66+
"stack": "Cli-Test"
67+
},
68+
"scheduler": {
69+
"tags": {
70+
"apps": "true"
71+
}
72+
},
73+
"external_links": [],
74+
"environment": {
75+
"EXAMPLE": "value"
76+
}
77+
}
78+
}
79+
}
80+
```

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
},
1818
"require": {
1919
"php": "^7.0",
20-
"ipunkt/rancherize": "^2.11.3"
20+
"ipunkt/rancherize": "^2.14.2"
2121
},
2222

2323
"extra":{

plugin/PhpCliBlueprint/PhpCliBlueprint.php

Lines changed: 192 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
<?php namespace RancherizeBlueprintPhpCli\PhpCliBlueprint;
22

3+
use Closure;
34
use Rancherize\Blueprint\Blueprint;
5+
use Rancherize\Blueprint\Cron\CronService\CronService;
6+
use Rancherize\Blueprint\Cron\Schedule\Exceptions\NoScheduleConfiguredException;
7+
use Rancherize\Blueprint\Cron\Schedule\ScheduleParser;
48
use Rancherize\Blueprint\Flags\HasFlagsTrait;
59
use Rancherize\Blueprint\Infrastructure\Dockerfile\Dockerfile;
610
use Rancherize\Blueprint\Infrastructure\Infrastructure;
11+
use Rancherize\Blueprint\Infrastructure\Service\Service;
12+
use Rancherize\Blueprint\Infrastructure\Service\Services\AppService;
713
use Rancherize\Blueprint\Scheduler\SchedulerInitializer\SchedulerInitializer;
14+
use Rancherize\Blueprint\Scheduler\SchedulerParser\SchedulerParser;
15+
use Rancherize\Blueprint\TakesDockerAccount;
816
use Rancherize\Blueprint\Validation\Exceptions\ValidationFailedException;
917
use Rancherize\Blueprint\Validation\Traits\HasValidatorTrait;
1018
use Rancherize\Configuration\Configurable;
@@ -14,14 +22,17 @@
1422
use Rancherize\Configuration\Services\ConfigurableFallback;
1523
use Rancherize\Configuration\Services\ConfigurationFallback;
1624
use Rancherize\Configuration\Services\ConfigurationInitializer;
25+
use Rancherize\Docker\DockerAccount;
1726
use Symfony\Component\Console\Input\InputInterface;
1827
use Symfony\Component\Console\Output\OutputInterface;
1928

2029
/**
2130
* Class PhpCliBlueprint
2231
* @package RancherizeBlueprintPhpCli\PhpCliBlueprint
2332
*/
24-
class PhpCliBlueprint implements Blueprint {
33+
class PhpCliBlueprint implements Blueprint, TakesDockerAccount {
34+
35+
private $targetDirectory = '/var/cli/app';
2536

2637
/**
2738
* Provider $this->getFlag('dev', false) to detect `rancherize init php-cli --dev` in init.
@@ -30,6 +41,11 @@ class PhpCliBlueprint implements Blueprint {
3041

3142
use HasValidatorTrait;
3243

44+
/**
45+
* @var SchedulerParser
46+
*/
47+
protected $rancherSchedulerParser;
48+
3349
/**
3450
* Fill the configurable with all possible options with explanatory default options set
3551
*
@@ -148,6 +164,11 @@ public function build( Configuration $configuration, string $environment, string
148164
$infrastructure->setDockerfile($dockerfile);
149165

150166
// TODO: Implement build() method.
167+
$service = $this->makeServerService($config, $projectConfigurable);
168+
$infrastructure->addService($service);
169+
$this->addAppContainer($version, $config, $service, $infrastructure);
170+
171+
$this->parseCronSchedule( $config, $service );
151172

152173
return $infrastructure;
153174
}
@@ -159,18 +180,23 @@ public function build( Configuration $configuration, string $environment, string
159180
protected function makeDockerfile(Configuration $config):Dockerfile {
160181
$dockerfile = new Dockerfile();
161182

162-
$baseimage = $config->has('php')
163-
? 'php:' . $config->get('php', '7.0') . '-alpine'
164-
: $config->get('docker.base-image', 'php:7.0-alpine');
183+
/**
184+
* @IMPORTANT
185+
*
186+
* This is NOT the php version that will later run the image.
187+
* It is the base of the app DATA image.
188+
* The php image that will actually run the app is the one set for the ServerService with $serverService->setImage()
189+
*/
190+
$baseimage = $config->get('docker.base-image', 'php:7.0-alpine');
165191
$dockerfile->setFrom($baseimage);
166192

167-
$dockerfile->addVolume('/var/www/app');
193+
$dockerfile->addVolume( $this->targetDirectory );
168194

169-
$dockerfile->setWorkdir('/var/www/app');
195+
$dockerfile->setWorkdir( $this->targetDirectory );
170196

171197
$copySuffix = $config->get('work-sub-directory', '');
172198
$targetSuffix = $config->get('target-sub-directory', '');
173-
$dockerfile->copy('.'.$copySuffix, '/var/www/app'.$targetSuffix);
199+
$dockerfile->copy('.'.$copySuffix, $this->targetDirectory .$targetSuffix);
174200

175201
if ($config->get('add-composer', false)) {
176202
$dockerfile->run('php -r "copy(\'https://getcomposer.org/installer\', \'composer-setup.php\');" \
@@ -192,11 +218,168 @@ protected function makeDockerfile(Configuration $config):Dockerfile {
192218
$dockerfile->addVolume($path);
193219
}
194220
}
195-
$dockerfile->run('rm -Rf /var/www/app/.rancherize');
221+
$dockerfile->run('rm -Rf '.$this->targetDirectory.'/.rancherize');
196222

197-
$dockerfile->setCommand('php '.$config->get('command', '-i'));
198223

199224
return $dockerfile;
200225
}
201226

227+
/**
228+
* @param Configuration $config
229+
* @param Configuration $default
230+
* @return Service
231+
*/
232+
protected function makeServerService(Configuration $config, Configuration $default) : Service {
233+
$serverService = new Service();
234+
$serverService->setName($config->get('service-name'));
235+
236+
$phpImage = $config->has('php')
237+
? 'php:' . $config->get('php', '7.0') . '-alpine'
238+
: $config->get('docker.base-image', 'php:7.0-alpine');
239+
$serverService->setImage($config->get('docker.image', $phpImage));
240+
241+
if( $config->get('sync-user-into-container', false) ) {
242+
$serverService->setEnvironmentVariable('USER_ID', getmyuid());
243+
$serverService->setEnvironmentVariable('GROUP_ID', getmygid());
244+
}
245+
246+
if ($config->get('mount-workdir', false)) {
247+
$mountSuffix = $config->get('work-sub-directory', '');
248+
$targetSuffix = $config->get('target-sub-directory', '');
249+
250+
$hostDirectory = getcwd() . $mountSuffix;
251+
$containerDirectory = $this->targetDirectory . $targetSuffix;
252+
$serverService->addVolume($hostDirectory, $containerDirectory);
253+
}
254+
255+
256+
$command = 'php ' . $config->get( 'command', '-i' );
257+
$serverService->setCommand($command);
258+
$serverService->setRestart( Service::RESTART_START_ONCE );
259+
$serverService->setWorkDir( $this->targetDirectory );
260+
261+
$persistentDriver = $config->get('docker.persistent-driver', 'pxd');
262+
$persistentOptions = $config->get('docker.persistent-options', [
263+
'repl' => '3',
264+
'shared' => 'true',
265+
]);
266+
foreach( $config->get('persistent-volumes', []) as $volumeName => $path ) {
267+
$volume = new \Rancherize\Blueprint\Infrastructure\Service\Volume();
268+
$volume->setDriver($persistentDriver);
269+
$volume->setOptions($persistentOptions);
270+
$volume->setExternalPath($volumeName);
271+
$volume->setInternalPath($path);
272+
$serverService->addVolume( $volume );
273+
}
274+
275+
$this->addAll([$default, $config], 'environment', function(string $name, $value) use ($serverService) {
276+
$serverService->setEnvironmentVariable($name, $value);
277+
});
278+
279+
$this->addAll([$default, $config], 'labels', function(string $name, $value) use ($serverService) {
280+
$serverService->addLabel($name, $value);
281+
});
282+
283+
if ($config->has('external_links')) {
284+
foreach ($config->get('external_links') as $name => $value)
285+
$serverService->addExternalLink($value, $name);
286+
}
287+
288+
$this->rancherSchedulerParser->parse($serverService, $config);
289+
290+
return $serverService;
291+
}
292+
293+
/**
294+
* @param Configuration[] $configs
295+
* @param string $label
296+
* @param Closure $closure
297+
*/
298+
private function addAll(array $configs, string $label, Closure $closure) {
299+
foreach($configs as $c) {
300+
if(!$c->has($label))
301+
continue;
302+
303+
foreach ($c->get($label) as $name => $value)
304+
$closure($name, $value);
305+
}
306+
}
307+
308+
/**
309+
* @param $config
310+
* @param $service
311+
*/
312+
protected function parseCronSchedule( $config, $service ) {
313+
/**
314+
* @var ScheduleParser $scheduleParser
315+
*/
316+
$scheduleParser = container( 'schedule-parser' );
317+
try {
318+
$schedule = $scheduleParser->parseSchedule( $config );
319+
} catch ( NoScheduleConfiguredException $e) {
320+
return;
321+
}
322+
323+
/**
324+
* @var CronService $cronService
325+
*/
326+
$cronService = container( 'cron-service' );
327+
$cronService->makeCron( $service, $schedule );
328+
}
329+
330+
/**
331+
* @param string $version
332+
* @param Configuration $config
333+
* @param Service $serverService
334+
* @param Infrastructure $infrastructure
335+
*/
336+
protected function addAppContainer($version, Configuration $config, Service $serverService, Infrastructure $infrastructure) {
337+
if (!$config->get('use-app-container', true))
338+
return;
339+
340+
$imageName = $config->get('docker.repository') . ':' . $config->get('docker.version-prefix') . $version;
341+
$imageNameWithServer = $this->applyServer($imageName);
342+
343+
$appService = new AppService($imageNameWithServer);
344+
$appService->setName($config->get('service-name') . 'App');
345+
346+
$serverService->addSidekick($appService);
347+
$serverService->addVolumeFrom($appService);
348+
$infrastructure->addService($appService);
349+
}
350+
351+
/**
352+
* @var DockerAccount
353+
*/
354+
protected $dockerAccount = null;
355+
356+
protected function applyServer(string $imageName) {
357+
if( $this->dockerAccount === null)
358+
return $imageName;
359+
360+
$server = $this->dockerAccount->getServer();
361+
if( empty($server) )
362+
return $imageName;
363+
364+
$serverHost = parse_url($server, PHP_URL_HOST);
365+
$imageNameWithServer = $serverHost.'/'.$imageName;
366+
367+
return $imageNameWithServer;
368+
}
369+
370+
/**
371+
* @param DockerAccount $dockerAccount
372+
* @return $this
373+
*/
374+
public function setDockerAccount( DockerAccount $dockerAccount ) {
375+
$this->dockerAccount = $dockerAccount;
376+
return $this;
377+
}
378+
379+
/**
380+
* @param SchedulerParser $rancherSchedulerParser
381+
*/
382+
public function setRancherSchedulerParser( SchedulerParser $rancherSchedulerParser ) {
383+
$this->rancherSchedulerParser = $rancherSchedulerParser;
384+
}
202385
}

plugin/RancherBlueprintPhpCliProvider.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?php namespace RancherizeBlueprintPhpCli;
22

3+
use Pimple\Container;
34
use Rancherize\Blueprint\Factory\BlueprintFactory;
45
use Rancherize\Plugin\Provider;
56
use Rancherize\Plugin\ProviderTrait;
@@ -26,6 +27,12 @@ public function boot() {
2627
*/
2728
$blueprintFactory = container('blueprint-factory');
2829

29-
$blueprintFactory->add('php-cli', PhpCliBlueprint::class);
30+
$blueprintFactory->add('php-cli', function(Container $c) {
31+
$blueprint = new PhpCliBlueprint;
32+
33+
$blueprint->setRancherSchedulerParser( $c['scheduler-parser'] );
34+
35+
return $blueprint;
36+
});
3037
}
3138
}

0 commit comments

Comments
 (0)