Skip to content

Allow admins to customizer docker script executors #2971

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 54 commits into from
Apr 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
243d055
Move PHP executor to its own package
nolanpro Feb 21, 2020
86add60
Add frontend resources to update user-editable dockerfile
nolanpro Feb 22, 2020
a1f01c5
Remove unused controller
nolanpro Feb 22, 2020
d36daf3
Add artisan command to build executor containers
nolanpro Feb 22, 2020
4ec5338
Add the storage folder for docker configs
nolanpro Feb 24, 2020
69684fe
Rename userDockerfile to appDockerfile for clarity
nolanpro Mar 6, 2020
3b55b62
Start on interface to rebuild script executors
nolanpro Mar 6, 2020
7d1e10a
Merge branch 'develop' into feature/2887
nolanpro Mar 6, 2020
dba2f92
Update build executor scripts
nolanpro Mar 10, 2020
6c43ea5
Move Lua to its own package
nolanpro Mar 10, 2020
ef1991f
Add disabled flag to cancel button
nolanpro Mar 10, 2020
b80f9e9
Merge branch 'develop' into feature/2887
nolanpro Mar 11, 2020
d704ae1
Move node script config to its package and update builder
nolanpro Mar 12, 2020
4f301a3
Extend timeout for build job
nolanpro Mar 18, 2020
5dc566f
Update build script
nolanpro Mar 18, 2020
3727d1d
Fix annotations
nolanpro Mar 18, 2020
0b792de
Add cancel ability to custom builds
nolanpro Mar 18, 2020
340315e
Merge branch 'develop' into feature/2887
nolanpro Mar 18, 2020
fe012d5
Add script executor migrations
nolanpro Mar 19, 2020
c362051
Add script executor models and migrations
nolanpro Mar 19, 2020
add746b
Remove unused docker build files
nolanpro Mar 19, 2020
0d9bb96
Update builder to only build a single base image
nolanpro Mar 19, 2020
72e06cd
Update script runner to reference executor id in image
nolanpro Mar 19, 2020
2721d59
Update UI to get script executors
nolanpro Mar 20, 2020
2897394
Update to get available languages
nolanpro Mar 20, 2020
00281c5
Add form validation to script executors
nolanpro Mar 20, 2020
7d05f84
Set the default executor when creating/updating a script
nolanpro Mar 21, 2020
3283888
Add a list function for selecting the executor from a dropdown
nolanpro Mar 21, 2020
92f4ea8
Allow the user to specify a script executor
nolanpro Mar 23, 2020
30da05e
Update script exitor to use executor instad of language
nolanpro Mar 23, 2020
ffa27a7
Add ability to delete script executor
nolanpro Mar 23, 2020
92f831d
Set the language on a script if only the executor is supplied
nolanpro Mar 23, 2020
de0ef0d
Update script executor modal title
nolanpro Mar 23, 2020
67cbb89
Merge branch 'develop' into feature/2887
nolanpro Mar 23, 2020
af513a1
Merge branch 'develop' into feature/2887
velkymx Mar 24, 2020
fd89308
Merge branch 'develop' into feature/2887
nolanpro Mar 24, 2020
91b9404
Add package files back in
nolanpro Mar 24, 2020
6af5d7c
Fix tests related to running scripts
nolanpro Mar 24, 2020
67dfeff
Add temporary github repos
nolanpro Mar 24, 2020
12631ce
Fix composer repo key names
nolanpro Mar 24, 2020
e5a445f
Merge branch 'develop' into feature/2887
nolanpro Mar 24, 2020
fd3fed7
Configure minimum-stability dev
nolanpro Mar 24, 2020
1a12334
Update settings for circleci
nolanpro Mar 25, 2020
987109c
Add lua executor when testing
nolanpro Mar 25, 2020
8498b74
Merge branch 'develop' into feature/2887
nolanpro Mar 25, 2020
b39f912
Clear composer cache in ci
nolanpro Mar 25, 2020
9460df1
Merge branch 'develop' into feature/2887
nolanpro Mar 25, 2020
5cb6928
Add docker layer caching
nolanpro Mar 25, 2020
7ad4574
Specify packagist verisons
nolanpro Mar 25, 2020
ad2b04a
Fix additional tests
nolanpro Mar 26, 2020
7a05c56
Merge branch 'develop' into feature/2887
nolanpro Mar 31, 2020
13c3123
Remove temporary circleci configs
nolanpro Mar 31, 2020
814a481
Merge branch 'develop' into feature/2887
nolanpro Mar 31, 2020
752513d
Run the executor install commands before phpunit
nolanpro Apr 1, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 26 additions & 25 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ jobs:
# documented at https://circleci.com/docs/2.0/circleci-images/
- image: circleci/mysql:5.7-ram
environment:
- MYSQL_ROOT_PASSWORD: P4ssW0rd1!
- MYSQL_DATABASE: circle_test
MYSQL_ROOT_PASSWORD: P4ssW0rd1!
MYSQL_DATABASE: circle_test

# Add support for Microsoft SQL Server Testing
- image: microsoft/mssql-server-linux:2017-GA
environment:
# Needed for MS SQL Docker install
- ACCEPT_EULA: 'Y'
- SA_PASSWORD: 'P4ssW0rd1!'
ACCEPT_EULA: 'Y'
SA_PASSWORD: 'P4ssW0rd1!'

working_directory: ~/repo

Expand Down Expand Up @@ -112,27 +112,28 @@ jobs:

# Enable xdebug to support code coverage
#- run: sudo docker-php-ext-enable xdebug

- setup_remote_docker:
docker_layer_caching: true

- setup_remote_docker

- run:
name: setup SDKs
command: |
php artisan l5:generate
mkdir -p /tmp/processmaker-sdk-php
php artisan processmaker:sdk php /tmp/processmaker-sdk-php
mkdir -p /tmp/processmaker-sdk-node
php artisan processmaker:sdk javascript /tmp/processmaker-sdk-node
mkdir -p /tmp/processmaker-sdk-lua
php artisan processmaker:sdk lua /tmp/processmaker-sdk-lua
- run:
name: Configure scripts executor
command: |
docker pull processmaker4/executor-php:latest
docker pull processmaker4/executor-lua:latest
docker pull processmaker4/executor-node:latest
docker pull jbergknoff/sass:latest
sudo mkdir -m777 /opt/executor
# - run:
# name: setup SDKs
# command: |
# php artisan l5:generate
# mkdir -p /tmp/processmaker-sdk-php
# php artisan processmaker:sdk php /tmp/processmaker-sdk-php
# mkdir -p /tmp/processmaker-sdk-node
# php artisan processmaker:sdk javascript /tmp/processmaker-sdk-node
# mkdir -p /tmp/processmaker-sdk-lua
# php artisan processmaker:sdk lua /tmp/processmaker-sdk-lua
# - run:
# name: Configure scripts executor
# command: |
# docker pull processmaker4/executor-php:latest
# docker pull processmaker4/executor-lua:latest
# docker pull processmaker4/executor-node:latest
# docker pull jbergknoff/sass:latest
# sudo mkdir -m777 /opt/executor
#- run: sudo docker-php-ext-enable xdebug

# Build frontend assets for production
Expand Down Expand Up @@ -165,7 +166,7 @@ jobs:
MSSQL_DATABASE: 'test'
MSSQL_USERNAME: 'sa'
MSSQL_PASSWORD: 'P4ssW0rd1!'
PROCESSMAKER_SCRIPTS_HOME: '/opt/executor'
PROCESSMAKER_SCRIPTS_HOME: '/tmp'
PROCESSMAKER_SCRIPTS_DOCKER_MODE: 'copying'
TELESCOPE_ENABLED: 'false'
- run:
Expand Down
186 changes: 186 additions & 0 deletions ProcessMaker/Console/Commands/BuildScriptExecutors.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
<?php

namespace ProcessMaker\Console\Commands;

use Illuminate\Console\Command;
use ProcessMaker\Events\BuildScriptExecutor;
use ProcessMaker\BuildSdk;
use ProcessMaker\Models\ScriptExecutor;
use \Exception;

class BuildScriptExecutors extends Command
{
/**
* The name and signature of the console command.
*
*
* @var string
*/
protected $signature = 'processmaker:build-script-executor {lang} {user?}';

/**
* The console command description.
*
* @var string
*/
protected $description = '';

/**
* The user ID to send the broadcast event to.
*
* @var int
*/
protected $userId = null;

/**
* The path to save the current running process id
*
* @var string
*/
protected $pidFilePath = null;

/**
* The path to the executor package
*
* @var string
*/
protected $packagePath = null;

/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}

/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$this->userId = $this->argument('user');
try {
$this->buildExecutor();
} catch (\Exception $e) {
if ($this->userId) {
event(new BuildScriptExecutor($e->getMessage(), $this->userId, 'error'));
}
throw new \Exception($e->getMessage());
} finally {
if ($this->packagePath && file_exists($this->packagePath . '/Dockerfile.custom')) {
unlink($this->packagePath . '/Dockerfile.custom');
}
if ($this->pidFilePath) {
unlink($this->pidFilePath);
}
}
}

public function buildExecutor()
{
$this->savePid();
$this->sendEvent($this->pidFilePath, 'starting');

$langArg = $this->argument('lang');
if (is_numeric($langArg)) {
$scriptExecutor = ScriptExecutor::findOrFail($langArg);
} else {
$scriptExecutor = ScriptExecutor::initialExecutor($langArg);
}
$lang = $scriptExecutor->language;

$this->info("Building for language: $lang");
$this->info("Generating SDK json document");
$this->artisan('l5-swagger:generate');

$this->packagePath = $packagePath =
ScriptExecutor::packagePath($lang);

$sdkDir = $packagePath . "/sdk";

if (!is_dir($sdkDir)) {
mkdir($sdkDir, 0755, true);
}

$this->info("Building the SDK");
$this->artisan("processmaker:sdk $lang $sdkDir --clean");
$this->info("SDK is at ${sdkDir}");

$dockerfile = ScriptExecutor::initDockerfile($lang) . "\n" . $scriptExecutor->config;

$this->info("Dockerfile:\n " . implode("\n ", explode("\n", $dockerfile)));
file_put_contents($packagePath . '/Dockerfile.custom', $dockerfile);

$this->info("Building the docker executor");

$image = $scriptExecutor->dockerImageName();
$command = "docker build --build-arg SDK_DIR=/sdk -t ${image} -f ${packagePath}/Dockerfile.custom ${packagePath}";

if ($this->userId) {
$this->runProc(
$command,
function() {
// Command starting
},
function($output) {
// Command output callback
$this->sendEvent($output, 'running');
},
function($exitCode) {
// Command finished callback
$this->sendEvent($exitCode, 'done');
}
);
} else {
system($command);
}
}

public function info($text, $verbosity = null) {
if ($this->userId) {
$this->sendEvent($text . "\n", 'running');
}
parent::info($text, $verbosity);
}

private function sendEvent($output, $status)
{
event(new BuildScriptExecutor($output, $this->userId, $status));
}

private function artisan($cmd)
{
\Artisan::call($cmd);
}

private function savePid()
{
$pid = getmypid();
$this->pidFilePath = tempnam('/tmp', 'build_script_executor_');
file_put_contents($this->pidFilePath, $pid);
}

private function runProc($cmd, $start, $callback, $done)
{
$dsc = [['pipe', 'r'], ['pipe', 'w'], ['pipe', 'w']];
$process = proc_open("($cmd) 2>&1", $dsc, $pipes);

$start();

while(!feof($pipes[1])) {
$callback(fgets($pipes[1]));
}

fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);

$exitCode = proc_close($process);
$done($exitCode);
}
}
49 changes: 22 additions & 27 deletions ProcessMaker/Console/Commands/GenerateSdk.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,35 +40,30 @@ public function __construct()
*/
public function handle()
{
try {
$jsonPath = base_path('storage/api-docs/api-docs.json');
$builder = new BuildSdk($jsonPath, $this->argument('output'), false);
if ($this->argument('language') === 'none') {
$this->info(
"No language specified. Choose one of these: \n" .
join(", ", $builder->getAvailableLanguages())
);
return;
}
$builder->setLang($this->argument('language'));
if ($this->options()['list-options']) {
$this->info($builder->getOptions());
return;
}
$jsonPath = base_path('storage/api-docs/api-docs.json');
$builder = new BuildSdk($jsonPath, $this->argument('output'), false);
if ($this->argument('language') === 'none') {
$this->info(
"No language specified. Choose one of these: \n" .
join(", ", $builder->getAvailableLanguages())
);
return;
}
$builder->setLang($this->argument('language'));
if ($this->options()['list-options']) {
$this->info($builder->getOptions());
return;
}

// Delete all files except .git folder
if ($this->options()['clean']) {
$folder = $this->argument('output');
if (substr($folder, -1) !== '/') {
$folder .= "/";
}
exec('rm -rf ' . $folder . '*');
// Delete all files except .git folder
if ($this->options()['clean']) {
$folder = $this->argument('output');
if (substr($folder, -1) !== '/') {
$folder .= "/";
}

$this->info($builder->run());
} catch(Exception $e) {
echo "ERROR: {$e->getMessage()}\n";
exit(1);
exec('rm -rf ' . $folder . '*');
}

$this->info($builder->run());
}
}
27 changes: 27 additions & 0 deletions ProcessMaker/Events/BuildScriptExecutor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php
namespace ProcessMaker\Events;

use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
use Illuminate\Broadcasting\PrivateChannel;

class BuildScriptExecutor implements ShouldBroadcastNow {
public $output;
public $userId;
public $status;

public function __construct($output, $userId, $status)
{
$this->output = $output;
$this->userId = $userId;
$this->status = $status;
}

public function broadcastAs() {
return 'BuildScriptExecutor';
}

public function broadcastOn()
{
return new PrivateChannel('ProcessMaker.Models.User.' . $this->userId);
}
}
14 changes: 14 additions & 0 deletions ProcessMaker/Http/Controllers/Admin/ScriptExecutorController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace ProcessMaker\Http\Controllers\Admin;

use Illuminate\Http\Request;
use ProcessMaker\Http\Controllers\Controller;

class ScriptExecutorController extends Controller
{
public function index(Request $request)
{
return view('admin.script-executors.index');
}
}
Loading