From 63554335cf088701806b8ea7443ccd7470785e0a Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Fri, 10 Aug 2018 15:54:59 +0530 Subject: [PATCH 01/81] Get image versions from utils Signed-off-by: Riddhesh Sanghvi --- src/Site_Docker.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Site_Docker.php b/src/Site_Docker.php index d025914c..5eabd87e 100644 --- a/src/Site_Docker.php +++ b/src/Site_Docker.php @@ -12,14 +12,15 @@ class Site_Docker { * @return String docker-compose.yml content string. */ public function generate_docker_compose_yml( array $filters = [] ) { - $base = []; + $img_versions = EE\Utils\get_image_versions(); + $base = []; $restart_default = [ 'name' => 'always' ]; $network_default = [ 'name' => 'site-network' ]; // nginx configuration. $nginx['service_name'] = [ 'name' => 'nginx' ]; - $nginx['image'] = [ 'name' => 'easyengine/nginx:v' . EE_VERSION ]; + $nginx['image'] = [ 'name' => 'easyengine/nginx:' . $img_versions['easyengine/nginx'] ]; $nginx['restart'] = $restart_default; $v_host = 'VIRTUAL_HOST'; From c6ff8ac53c41fca655cc86525623aa28f9d57997 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Fri, 10 Aug 2018 16:07:38 +0530 Subject: [PATCH 02/81] Remove version change in travis for docker-images Signed-off-by: Riddhesh Sanghvi --- ci/prepare.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/ci/prepare.sh b/ci/prepare.sh index 399d6e9c..3535cfce 100755 --- a/ci/prepare.sh +++ b/ci/prepare.sh @@ -10,7 +10,6 @@ rm ee cd .. git clone https://github.com/EasyEngine/easyengine.git easyengine --depth=1 cd easyengine -echo 'travis_test' > VERSION # Copy tests to EE repo rm -r features From 67e8f6946c5c383f7d4e241344620742bf7bf7bf Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar Date: Fri, 10 Aug 2018 20:04:02 +0530 Subject: [PATCH 03/81] Refactor to accommodate new DB changes Signed-off-by: Kirtan Gajjar --- src/Site_Command.php | 45 ++++++++++++++++---------------------------- 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/src/Site_Command.php b/src/Site_Command.php index a78f2976..ede385f1 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -13,15 +13,11 @@ * @package ee-cli */ +use EE\Model\Site; use \Symfony\Component\Filesystem\Filesystem; class Site_Command extends EE_Site_Command { - /** - * @var string $command Name of the command being run. - */ - private $command; - /** * @var array $site Associative array containing essential site related information. */ @@ -57,22 +53,15 @@ class Site_Command extends EE_Site_Command { */ private $fs; - /** - * @var Object $db Object to access `EE::db()` functions. - */ - private $db; - public function __construct() { $this->level = 0; - $this->command = 'site'; pcntl_signal( SIGTERM, [ $this, "rollback" ] ); pcntl_signal( SIGHUP, [ $this, "rollback" ] ); pcntl_signal( SIGUSR1, [ $this, "rollback" ] ); pcntl_signal( SIGINT, [ $this, "rollback" ] ); $shutdown_handler = new Shutdown_Handler(); register_shutdown_function( [ $shutdown_handler, "cleanup" ], [ &$this ] ); - $this->db = EE::db(); $this->docker = EE::docker(); $this->logger = EE::get_file_logger()->withName( 'site_command' ); $this->fs = new Filesystem(); @@ -107,7 +96,7 @@ public function create( $args, $assoc_args ) { EE::error( sprintf( 'Invalid site-type: %s', $this->site['type'] ) ); } - if ( $this->db::site_in_db( $this->site['name'] ) ) { + if ( Site::find( $this->site['name'] ) ) { EE::error( sprintf( "Site %1\$s already exists. If you want to re-create it please delete the older one using:\n`ee site delete %1\$s`", $this->site['name'] ) ); } @@ -132,7 +121,7 @@ public function info( $args, $assoc_args ) { EE\Utils\delem_log( 'site info start' ); if ( ! isset( $this->site['name'] ) ) { - $args = EE\SiteUtils\auto_site_name( $args, $this->command, __FUNCTION__ ); + $args = EE\SiteUtils\auto_site_name( $args, 'site', __FUNCTION__ ); $this->populate_site_info( $args ); } $ssl = $this->le ? 'Enabled' : 'Not Enabled'; @@ -238,18 +227,17 @@ private function create_site() { */ private function create_site_db_entry() { - $ssl = $this->le ? 1 : 0; - $data = [ - 'sitename' => $this->site['name'], + $ssl = $this->le ? 'letsencrypt' : null ; + + $site = Site::create([ + 'site_url' => $this->site['name'], 'site_type' => $this->site['type'], - 'site_path' => $this->site['root'], - 'site_command' => $this->command, - 'is_ssl' => $ssl, - 'created_on' => date( 'Y-m-d H:i:s', time() ), - ]; + 'site_fs_path' => $this->site['root'], + 'site_ssl' => $ssl, + ]); try { - if ( $this->db::insert( $data ) ) { + if ( $site ) { EE::log( 'Site entry created.' ); } else { throw new Exception( 'Error creating site entry in database.' ); @@ -266,13 +254,12 @@ private function populate_site_info( $args ) { $this->site['name'] = EE\Utils\remove_trailing_slash( $args[0] ); - if ( $this->db::site_in_db( $this->site['name'] ) ) { - - $db_select = $this->db::select( [], [ 'sitename' => $this->site['name'] ], 'sites', 1 ); + $site = Site::find( $this->site['name'] ); - $this->site['type'] = $db_select['site_type']; - $this->site['root'] = $db_select['site_path']; - $this->le = $db_select['is_ssl']; + if ( $site ) { + $this->site['type'] = $site->site_type; + $this->site['root'] = $site->site_fs_path; + $this->le = $site->site_ssl; } else { EE::error( sprintf( 'Site %s does not exist.', $this->site['name'] ) ); From 95470545b407ae530b84e278c0daf08cf9c8fac5 Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar Date: Mon, 13 Aug 2018 16:13:02 +0530 Subject: [PATCH 04/81] Change name to url Signed-off-by: Kirtan Gajjar --- src/Site_Command.php | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/Site_Command.php b/src/Site_Command.php index ede385f1..d9561931 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -90,14 +90,14 @@ public function create( $args, $assoc_args ) { EE::warning( 'This is a beta version. Please don\'t use it in production.' ); $this->logger->debug( 'args:', $args ); $this->logger->debug( 'assoc_args:', empty( $assoc_args ) ? [ 'NULL' ] : $assoc_args ); - $this->site['name'] = strtolower( EE\Utils\remove_trailing_slash( $args[0] ) ); + $this->site['url'] = strtolower( EE\Utils\remove_trailing_slash( $args[0] ) ); $this->site['type'] = EE\Utils\get_flag_value( $assoc_args, 'type', 'html' ); if ( 'html' !== $this->site['type'] ) { EE::error( sprintf( 'Invalid site-type: %s', $this->site['type'] ) ); } - if ( Site::find( $this->site['name'] ) ) { - EE::error( sprintf( "Site %1\$s already exists. If you want to re-create it please delete the older one using:\n`ee site delete %1\$s`", $this->site['name'] ) ); + if ( Site::find( $this->site['url'] ) ) { + EE::error( sprintf( "Site %1\$s already exists. If you want to re-create it please delete the older one using:\n`ee site delete %1\$s`", $this->site['url'] ) ); } $this->le = EE\Utils\get_flag_value( $assoc_args, 'letsencrypt' ); @@ -120,14 +120,14 @@ public function create( $args, $assoc_args ) { public function info( $args, $assoc_args ) { EE\Utils\delem_log( 'site info start' ); - if ( ! isset( $this->site['name'] ) ) { + if ( ! isset( $this->site['url'] ) ) { $args = EE\SiteUtils\auto_site_name( $args, 'site', __FUNCTION__ ); $this->populate_site_info( $args ); } $ssl = $this->le ? 'Enabled' : 'Not Enabled'; $prefix = ( $this->le ) ? 'https://' : 'http://'; $info = [ - [ 'Site', $prefix . $this->site['name'] ], + [ 'Site', $prefix . $this->site['url'] ], [ 'Site Root', $this->site['root'] ], [ 'SSL', $ssl ], ]; @@ -150,7 +150,7 @@ private function configure_site_files() { $site_src_dir = $this->site['root'] . '/app/src'; $process_user = posix_getpwuid( posix_geteuid() ); - EE::log( sprintf( 'Creating site %s.', $this->site['name'] ) ); + EE::log( sprintf( 'Creating site %s.', $this->site['url'] ) ); EE::log( 'Copying configuration files.' ); $filter = []; @@ -158,10 +158,10 @@ private function configure_site_files() { $filter[] = $this->le; $site_docker = new Site_Docker(); $docker_compose_content = $site_docker->generate_docker_compose_yml( $filter ); - $default_conf_content = $default_conf_content = EE\Utils\mustache_render( SITE_TEMPLATE_ROOT . '/config/nginx/default.conf.mustache', [ 'server_name' => $this->site['name'] ] ); + $default_conf_content = $default_conf_content = EE\Utils\mustache_render( SITE_TEMPLATE_ROOT . '/config/nginx/default.conf.mustache', [ 'server_name' => $this->site['url'] ] ); $env_data = [ - 'virtual_host' => $this->site['name'], + 'virtual_host' => $this->site['url'], 'user_id' => $process_user['uid'], 'group_id' => $process_user['gid'], ]; @@ -182,7 +182,7 @@ private function configure_site_files() { $this->fs->mkdir( $site_src_dir ); $this->fs->dumpFile( $site_src_dir . '/index.html', $index_html ); - EE\Siteutils\add_site_redirects( $this->site['name'], $this->le ); + EE\Siteutils\add_site_redirects( $this->site['url'], $this->le ); EE::success( 'Configuration files copied.' ); } catch ( Exception $e ) { @@ -195,30 +195,30 @@ private function configure_site_files() { */ private function create_site() { - $this->site['root'] = WEBROOT . $this->site['name']; + $this->site['root'] = WEBROOT . $this->site['url']; $this->level = 1; try { - EE\Siteutils\create_site_root( $this->site['root'], $this->site['name'] ); + EE\Siteutils\create_site_root( $this->site['root'], $this->site['url'] ); $this->level = 2; - EE\Siteutils\setup_site_network( $this->site['name'] ); + EE\Siteutils\setup_site_network( $this->site['url'] ); $this->level = 3; $this->configure_site_files(); EE\Siteutils\start_site_containers( $this->site['root'] ); - EE\Siteutils\create_etc_hosts_entry( $this->site['name'] ); + EE\Siteutils\create_etc_hosts_entry( $this->site['url'] ); if ( ! $this->skip_chk ) { $this->level = 4; - EE\Siteutils\site_status_check( $this->site['name'] ); + EE\Siteutils\site_status_check( $this->site['url'] ); } } catch ( Exception $e ) { $this->catch_clean( $e ); } if ( $this->le ) { - $this->init_le( $this->site['name'], $this->site['root'], false ); + $this->init_le( $this->site['url'], $this->site['root'], false ); } - $this->info( [ $this->site['name'] ], [] ); + $this->info( [ $this->site['url'] ], [] ); $this->create_site_db_entry(); } @@ -230,7 +230,7 @@ private function create_site_db_entry() { $ssl = $this->le ? 'letsencrypt' : null ; $site = Site::create([ - 'site_url' => $this->site['name'], + 'site_url' => $this->site['url'], 'site_type' => $this->site['type'], 'site_fs_path' => $this->site['root'], 'site_ssl' => $ssl, @@ -252,9 +252,9 @@ private function create_site_db_entry() { */ private function populate_site_info( $args ) { - $this->site['name'] = EE\Utils\remove_trailing_slash( $args[0] ); + $this->site['url'] = EE\Utils\remove_trailing_slash( $args[0] ); - $site = Site::find( $this->site['name'] ); + $site = Site::find( $this->site['url'] ); if ( $site ) { $this->site['type'] = $site->site_type; @@ -262,7 +262,7 @@ private function populate_site_info( $args ) { $this->le = $site->site_ssl; } else { - EE::error( sprintf( 'Site %s does not exist.', $this->site['name'] ) ); + EE::error( sprintf( 'Site %s does not exist.', $this->site['url'] ) ); } } @@ -292,7 +292,7 @@ private function catch_clean( $e ) { EE\Utils\delem_log( 'site cleanup start' ); EE::warning( $e->getMessage() ); EE::warning( 'Initiating clean-up.' ); - $this->delete_site( $this->level, $this->site['name'], $this->site['root'] ); + $this->delete_site( $this->level, $this->site['url'], $this->site['root'] ); EE\Utils\delem_log( 'site cleanup end' ); exit; } @@ -304,7 +304,7 @@ private function rollback() { EE::warning( 'Exiting gracefully after rolling back. This may take some time.' ); if ( $this->level > 0 ) { - $this->delete_site( $this->level, $this->site['name'], $this->site['root'] ); + $this->delete_site( $this->level, $this->site['url'], $this->site['root'] ); } EE::success( 'Rollback complete. Exiting now.' ); exit; From 367c6faab131c38d755188aaf01f3a21fe43bef4 Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar Date: Tue, 14 Aug 2018 13:15:26 +0530 Subject: [PATCH 05/81] Correct --ssl flag behaviour Signed-off-by: Kirtan Gajjar --- src/Site_Command.php | 47 +++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/src/Site_Command.php b/src/Site_Command.php index a78f2976..8a373c13 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -43,9 +43,14 @@ class Site_Command extends EE_Site_Command { private $logger; /** - * @var bool $le Whether the site is letsencrypt or not. + * @var bool $ssl Whether the site is has SSL enabled. */ - private $le; + private $ssl; + + /** + * @var bool $ssl_wildcard Whether the site SSL is wildcard. + */ + private $ssl_wildcard; /** * @var bool $skip_chk To skip site status check pre-installation. @@ -86,9 +91,11 @@ public function __construct() { * * : Name of website. * - * [--letsencrypt] + * [--ssl=] * : Enables ssl via letsencrypt certificate. * + * [--wildcard] + * : Gets wildcard SSL . * [--type=] * : Type of the site to be created. Values: html,php,wp. * @@ -111,8 +118,9 @@ public function create( $args, $assoc_args ) { EE::error( sprintf( "Site %1\$s already exists. If you want to re-create it please delete the older one using:\n`ee site delete %1\$s`", $this->site['name'] ) ); } - $this->le = EE\Utils\get_flag_value( $assoc_args, 'letsencrypt' ); - $this->skip_chk = EE\Utils\get_flag_value( $assoc_args, 'skip-status-check' ); + $this->ssl = EE\Utils\get_flag_value( $assoc_args, 'ssl' ); + $this->ssl_wildcard = EE\Utils\get_flag_value( $assoc_args, 'wildcard' ); + $this->skip_chk = EE\Utils\get_flag_value( $assoc_args, 'skip-status-check' ); EE\SiteUtils\init_checks(); @@ -135,14 +143,18 @@ public function info( $args, $assoc_args ) { $args = EE\SiteUtils\auto_site_name( $args, $this->command, __FUNCTION__ ); $this->populate_site_info( $args ); } - $ssl = $this->le ? 'Enabled' : 'Not Enabled'; - $prefix = ( $this->le ) ? 'https://' : 'http://'; + $ssl = $this->ssl ? 'Enabled' : 'Not Enabled'; + $prefix = ( $this->ssl ) ? 'https://' : 'http://'; $info = [ [ 'Site', $prefix . $this->site['name'] ], [ 'Site Root', $this->site['root'] ], [ 'SSL', $ssl ], ]; + if ( $this->ssl ) { + $info[] = [ 'SSL Wildcard', $this->ssl_wildcard ? 'Yes': 'No' ]; + } + EE\Utils\format_table( $info ); EE\Utils\delem_log( 'site info end' ); @@ -166,7 +178,6 @@ private function configure_site_files() { $filter = []; $filter[] = $this->site['type']; - $filter[] = $this->le; $site_docker = new Site_Docker(); $docker_compose_content = $site_docker->generate_docker_compose_yml( $filter ); $default_conf_content = $default_conf_content = EE\Utils\mustache_render( SITE_TEMPLATE_ROOT . '/config/nginx/default.conf.mustache', [ 'server_name' => $this->site['name'] ] ); @@ -193,7 +204,7 @@ private function configure_site_files() { $this->fs->mkdir( $site_src_dir ); $this->fs->dumpFile( $site_src_dir . '/index.html', $index_html ); - EE\Siteutils\add_site_redirects( $this->site['name'], $this->le ); + EE\Siteutils\add_site_redirects( $this->site['name'], $this->ssl ); EE::success( 'Configuration files copied.' ); } catch ( Exception $e ) { @@ -225,9 +236,14 @@ private function create_site() { } catch ( Exception $e ) { $this->catch_clean( $e ); } - - if ( $this->le ) { - $this->init_le( $this->site['name'], $this->site['root'], false ); + EE::debug( 'Starting SSL procedure' ); + + if ( 'le' === $this->ssl ) { + EE::debug( 'Initializing LE' ); + $this->init_le( $this->site['name'], $this->site['root'], $this->ssl_wildcard ); + } elseif ( 'inherit' === $this->ssl ) { + EE::debug( 'Inheriting certs' ); + $this->inherit_certs( $this->site['name'], $this->ssl_wildcard ); } $this->info( [ $this->site['name'] ], [] ); $this->create_site_db_entry(); @@ -238,13 +254,15 @@ private function create_site() { */ private function create_site_db_entry() { - $ssl = $this->le ? 1 : 0; + $ssl = $this->ssl ? 1 : 0; + $ssl_wildcard = $this->ssl_wildcard ? 1 : 0; $data = [ 'sitename' => $this->site['name'], 'site_type' => $this->site['type'], 'site_path' => $this->site['root'], 'site_command' => $this->command, 'is_ssl' => $ssl, + 'site_ssl_wildcard' => $ssl_wildcard, 'created_on' => date( 'Y-m-d H:i:s', time() ), ]; @@ -272,7 +290,8 @@ private function populate_site_info( $args ) { $this->site['type'] = $db_select['site_type']; $this->site['root'] = $db_select['site_path']; - $this->le = $db_select['is_ssl']; + $this->ssl = $db_select['is_ssl']; + $this->ssl_wildcard = $db_select['site_ssl_wildcard']; } else { EE::error( sprintf( 'Site %s does not exist.', $this->site['name'] ) ); From 83cffb5d02185c7bacc7fe21e849a1669e294432 Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar Date: Tue, 14 Aug 2018 17:01:37 +0530 Subject: [PATCH 06/81] Add error on incorrect --ssl param value Signed-off-by: Kirtan Gajjar --- src/Site_Command.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Site_Command.php b/src/Site_Command.php index 8a373c13..8d71c6ec 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -244,6 +244,8 @@ private function create_site() { } elseif ( 'inherit' === $this->ssl ) { EE::debug( 'Inheriting certs' ); $this->inherit_certs( $this->site['name'], $this->ssl_wildcard ); + } else { + EE::error( "Unrecognized value in --ssl flag: $this->ssl" ); } $this->info( [ $this->site['name'] ], [] ); $this->create_site_db_entry(); From e3e2265d7ebbd5399633cdc6d51f8886835f1741 Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar Date: Thu, 16 Aug 2018 14:19:17 +0530 Subject: [PATCH 07/81] Fix typo Signed-off-by: Kirtan Gajjar --- src/Site_Command.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Site_Command.php b/src/Site_Command.php index d9561931..6d1a9155 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -68,7 +68,7 @@ public function __construct() { } /** - * Runs the standard WordPress Site installation. + * Runs the standard WordPress site installation. * * ## OPTIONS * From 1acc44e0b67e4cb7b9f0e2b238269a0fd6f52427 Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar Date: Thu, 16 Aug 2018 18:14:53 +0530 Subject: [PATCH 08/81] Remove space after null Signed-off-by: Kirtan Gajjar --- src/Site_Command.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Site_Command.php b/src/Site_Command.php index 6d1a9155..a1485c20 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -227,7 +227,7 @@ private function create_site() { */ private function create_site_db_entry() { - $ssl = $this->le ? 'letsencrypt' : null ; + $ssl = $this->le ? 'letsencrypt' : null; $site = Site::create([ 'site_url' => $this->site['url'], From 4f6fa35d83b71abbd65f34c95400fa091b3a7709 Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar Date: Fri, 17 Aug 2018 16:36:41 +0530 Subject: [PATCH 09/81] Correct redirect block placement Signed-off-by: Kirtan Gajjar --- src/Site_Command.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Site_Command.php b/src/Site_Command.php index 8d71c6ec..7e774664 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -204,8 +204,6 @@ private function configure_site_files() { $this->fs->mkdir( $site_src_dir ); $this->fs->dumpFile( $site_src_dir . '/index.html', $index_html ); - EE\Siteutils\add_site_redirects( $this->site['name'], $this->ssl ); - EE::success( 'Configuration files copied.' ); } catch ( Exception $e ) { $this->catch_clean( $e ); @@ -247,6 +245,9 @@ private function create_site() { } else { EE::error( "Unrecognized value in --ssl flag: $this->ssl" ); } + + EE\Siteutils\add_site_redirects( $this->site['name'], $this->ssl ); + $this->info( [ $this->site['name'] ], [] ); $this->create_site_db_entry(); } From 7194812fe912625e47d3158226c8b828f22c0f2f Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar Date: Tue, 21 Aug 2018 18:37:26 +0530 Subject: [PATCH 10/81] Correct case of SiteUtils namespace Signed-off-by: Kirtan Gajjar --- src/Site_Command.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Site_Command.php b/src/Site_Command.php index 7e774664..96e58fde 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -218,15 +218,15 @@ private function create_site() { $this->site['root'] = WEBROOT . $this->site['name']; $this->level = 1; try { - EE\Siteutils\create_site_root( $this->site['root'], $this->site['name'] ); + EE\SiteUtils\create_site_root( $this->site['root'], $this->site['name'] ); $this->level = 2; - EE\Siteutils\setup_site_network( $this->site['name'] ); + EE\SiteUtils\setup_site_network( $this->site['name'] ); $this->level = 3; $this->configure_site_files(); - EE\Siteutils\start_site_containers( $this->site['root'] ); + EE\SiteUtils\start_site_containers( $this->site['root'] ); - EE\Siteutils\create_etc_hosts_entry( $this->site['name'] ); + EE\SiteUtils\create_etc_hosts_entry( $this->site['name'] ); if ( ! $this->skip_chk ) { $this->level = 4; EE\Siteutils\site_status_check( $this->site['name'] ); From 5f4ae99e1e9f28d0d378b7e6c06af2fd37ed5e56 Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar Date: Tue, 21 Aug 2018 18:50:55 +0530 Subject: [PATCH 11/81] Correct SSL and site redirection logic. Signed-off-by: Kirtan Gajjar --- src/Site_Command.php | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/Site_Command.php b/src/Site_Command.php index 96e58fde..6c9f0563 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -229,24 +229,29 @@ private function create_site() { EE\SiteUtils\create_etc_hosts_entry( $this->site['name'] ); if ( ! $this->skip_chk ) { $this->level = 4; - EE\Siteutils\site_status_check( $this->site['name'] ); + EE\SiteUtils\site_status_check( $this->site['name'] ); + } + + /* + * This adds http www redirection which is needed for issuing cert for a site. + * i.e. when you create example.com site, certs are issued for example.com and www.example.com + * + * We're issuing certs for both domains as it is needed in order to perform redirection of + * https://www.example.com -> https://example.com + * + * We add redirection config two times in case of ssl as we need http redirection + * when certs are being requested and http+https redirection after we have certs. + */ + EE\SiteUtils\add_site_redirects( $this->site['name'], false ); + EE\SiteUtils\reload_proxy_configuration(); + if ( $this->ssl ) { + $this->init_ssl( $this->site['name'], $this->site['root'], $this->ssl, $this->ssl_wildcard ); + EE\SiteUtils\add_site_redirects( $this->site['name'], true ); + EE\SiteUtils\reload_proxy_configuration(); } } catch ( Exception $e ) { $this->catch_clean( $e ); } - EE::debug( 'Starting SSL procedure' ); - - if ( 'le' === $this->ssl ) { - EE::debug( 'Initializing LE' ); - $this->init_le( $this->site['name'], $this->site['root'], $this->ssl_wildcard ); - } elseif ( 'inherit' === $this->ssl ) { - EE::debug( 'Inheriting certs' ); - $this->inherit_certs( $this->site['name'], $this->ssl_wildcard ); - } else { - EE::error( "Unrecognized value in --ssl flag: $this->ssl" ); - } - - EE\Siteutils\add_site_redirects( $this->site['name'], $this->ssl ); $this->info( [ $this->site['name'] ], [] ); $this->create_site_db_entry(); From 92fc974d519f29716707439e68ea814b62709ef8 Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar Date: Tue, 21 Aug 2018 20:22:38 +0530 Subject: [PATCH 12/81] Add inherit argument Signed-off-by: Kirtan Gajjar --- src/Site_Command.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Site_Command.php b/src/Site_Command.php index 6c9f0563..5930e263 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -242,11 +242,12 @@ private function create_site() { * We add redirection config two times in case of ssl as we need http redirection * when certs are being requested and http+https redirection after we have certs. */ - EE\SiteUtils\add_site_redirects( $this->site['name'], false ); + EE\SiteUtils\add_site_redirects( $this->site['name'], false, 'inherit' === $this->ssl ); EE\SiteUtils\reload_proxy_configuration(); + if ( $this->ssl ) { $this->init_ssl( $this->site['name'], $this->site['root'], $this->ssl, $this->ssl_wildcard ); - EE\SiteUtils\add_site_redirects( $this->site['name'], true ); + EE\SiteUtils\add_site_redirects( $this->site['name'], true, 'inherit' === $this->ssl ); EE\SiteUtils\reload_proxy_configuration(); } } catch ( Exception $e ) { From c5eb301daf9785e32ac39ff96c334f869f7f48c1 Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar Date: Tue, 21 Aug 2018 22:13:14 +0530 Subject: [PATCH 13/81] Replace site['name'] with site['url'] Signed-off-by: Kirtan Gajjar --- src/Site_Command.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Site_Command.php b/src/Site_Command.php index 1dd1d33e..0aef98a7 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -231,12 +231,12 @@ private function create_site() { * We add redirection config two times in case of ssl as we need http redirection * when certs are being requested and http+https redirection after we have certs. */ - EE\SiteUtils\add_site_redirects( $this->site['name'], false, 'inherit' === $this->ssl ); + EE\SiteUtils\add_site_redirects( $this->site['url'], false, 'inherit' === $this->ssl ); EE\SiteUtils\reload_proxy_configuration(); if ( $this->ssl ) { - $this->init_ssl( $this->site['name'], $this->site['root'], $this->ssl, $this->ssl_wildcard ); - EE\SiteUtils\add_site_redirects( $this->site['name'], true, 'inherit' === $this->ssl ); + $this->init_ssl( $this->site['url'], $this->site['root'], $this->ssl, $this->ssl_wildcard ); + EE\SiteUtils\add_site_redirects( $this->site['url'], true, 'inherit' === $this->ssl ); EE\SiteUtils\reload_proxy_configuration(); } } catch ( Exception $e ) { From 9a6081d430370337be4030d72e442a0c929a974a Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar Date: Tue, 21 Aug 2018 22:18:28 +0530 Subject: [PATCH 14/81] Remove site_command Signed-off-by: Kirtan Gajjar --- src/Site_Command.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Site_Command.php b/src/Site_Command.php index 0aef98a7..1074ef77 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -259,7 +259,6 @@ private function create_site_db_entry() { 'site_url' => $this->site['url'], 'site_type' => $this->site['type'], 'site_fs_path' => $this->site['root'], - 'site_command' => $this->command, 'site_ssl' => $ssl, 'site_ssl_wildcard' => $ssl_wildcard, 'created_on' => date( 'Y-m-d H:i:s', time() ), From 5e14dea7fdcd7cfa80b2d8d7f1a62260add972e1 Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar Date: Tue, 21 Aug 2018 22:39:31 +0530 Subject: [PATCH 15/81] Correct ssl flag Signed-off-by: Kirtan Gajjar --- features/redirect.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/redirect.feature b/features/redirect.feature index 273e3dbb..73d7d245 100644 --- a/features/redirect.feature +++ b/features/redirect.feature @@ -17,7 +17,7 @@ Feature: Site Redirection | Location: http://www.example1.test/ | Scenario: no_www-ssl redirection works properly - When I run 'sudo bin/ee site create example2.test --le --le-mail=test@test.com --skip-status-check' + When I run 'sudo bin/ee site create example2.test --ssl=le --skip-status-check' Then After delay of 5 seconds Then Request on 'localhost' with header 'Host: www.example2.test' should contain following headers: | header | @@ -29,7 +29,7 @@ Feature: Site Redirection | Location: https://example2.test/ | Scenario: www-ssl redirection works properly - When I run 'sudo bin/ee site create www.example3.test --le --le-mail=test@test.com --skip-status-check' + When I run 'sudo bin/ee site create www.example3.test --ssl=le --skip-status-check' Then After delay of 5 seconds Then Request on 'localhost' with header 'Host: example3.test' should contain following headers: | header | From 04899d5734eecd7753a9cb3697e5752b24cc8281 Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar Date: Wed, 22 Aug 2018 11:35:25 +0530 Subject: [PATCH 16/81] Add le-email in config Signed-off-by: Kirtan Gajjar --- features/bootstrap/FeatureContext.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index bec661c4..b9553169 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -65,6 +65,8 @@ public function __construct() { $this->commands = []; $this->ee_path = getcwd(); + $config_contents = \Mustangostang\Spyc::YAMLDump(['le-mail' => 'abc@example.com']); + file_put_contents( EE_CONF_ROOT . '/config.yml', $config_contents ); } /** From 4b925cc9220f1b95fa0e27dec4fd5fcbde7f01ef Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar Date: Thu, 23 Aug 2018 21:40:22 +0530 Subject: [PATCH 17/81] Define and add global network Signed-off-by: Kirtan Gajjar --- src/Site_Docker.php | 1 + templates/docker-compose.mustache | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Site_Docker.php b/src/Site_Docker.php index 5eabd87e..fd76f270 100644 --- a/src/Site_Docker.php +++ b/src/Site_Docker.php @@ -46,6 +46,7 @@ public function generate_docker_compose_yml( array $filters = [] ) { ], ]; $nginx['networks'] = $network_default; + $nginx['networks'] = [ 'name' => 'global-network' ]; $base[] = $nginx; diff --git a/templates/docker-compose.mustache b/templates/docker-compose.mustache index a0d9925c..9c6fac54 100644 --- a/templates/docker-compose.mustache +++ b/templates/docker-compose.mustache @@ -20,7 +20,7 @@ services: command: {{name}} {{/command}} {{#labels}} - labels: + labels: {{#label}} - "{{name}}" {{/label}} @@ -41,7 +41,6 @@ services: networks: - {{name}} {{/networks}} - {{/services}} {{#network}} @@ -49,4 +48,7 @@ networks: site-network: external: name: ${VIRTUAL_HOST} -{{/network}} \ No newline at end of file + global-network: + external: + name: ee-global-network +{{/network}} From 5528d72c87a7e4d7dc44e6f844bb9ac120bcba60 Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar Date: Fri, 24 Aug 2018 14:15:43 +0530 Subject: [PATCH 18/81] Remove setup site network call Signed-off-by: Kirtan Gajjar --- src/Site_Command.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Site_Command.php b/src/Site_Command.php index 1074ef77..e5b8c355 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -208,8 +208,6 @@ private function create_site() { $this->level = 1; try { EE\SiteUtils\create_site_root( $this->site['root'], $this->site['url'] ); - $this->level = 2; - EE\SiteUtils\setup_site_network( $this->site['url'] ); $this->level = 3; $this->configure_site_files(); From 1b1cc0bf5acc645d658cb877c28ffc3466d8d75f Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar Date: Fri, 24 Aug 2018 14:19:25 +0530 Subject: [PATCH 19/81] Add global and site network in docker-compose Also modify docker-compose mustache to support multiple network Signed-off-by: Kirtan Gajjar --- src/Site_Docker.php | 8 ++++++-- templates/docker-compose.mustache | 6 +++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Site_Docker.php b/src/Site_Docker.php index fd76f270..e4a7f787 100644 --- a/src/Site_Docker.php +++ b/src/Site_Docker.php @@ -45,8 +45,12 @@ public function generate_docker_compose_yml( array $filters = [] ) { 'name' => 'io.easyengine.site=${VIRTUAL_HOST}', ], ]; - $nginx['networks'] = $network_default; - $nginx['networks'] = [ 'name' => 'global-network' ]; + $nginx['networks'] = [ + 'net' => [ + $network_default, + [ 'name' => 'global-network' ], + ] + ]; $base[] = $nginx; diff --git a/templates/docker-compose.mustache b/templates/docker-compose.mustache index 9c6fac54..385a975d 100644 --- a/templates/docker-compose.mustache +++ b/templates/docker-compose.mustache @@ -39,15 +39,15 @@ services: {{/environment}} {{#networks}} networks: - - {{name}} + {{#net}} + - "{{name}}" + {{/net}} {{/networks}} {{/services}} {{#network}} networks: site-network: - external: - name: ${VIRTUAL_HOST} global-network: external: name: ee-global-network From 655087d9af2adabff1b3c72ee31d99e3a1a58a40 Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar Date: Fri, 24 Aug 2018 16:59:46 +0530 Subject: [PATCH 20/81] Add correct default network Signed-off-by: Kirtan Gajjar --- src/Site_Docker.php | 6 +++++- templates/docker-compose.mustache | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Site_Docker.php b/src/Site_Docker.php index e4a7f787..972e5156 100644 --- a/src/Site_Docker.php +++ b/src/Site_Docker.php @@ -16,7 +16,11 @@ public function generate_docker_compose_yml( array $filters = [] ) { $base = []; $restart_default = [ 'name' => 'always' ]; - $network_default = [ 'name' => 'site-network' ]; + $network_default = [ + 'net' => [ + [ 'name' => 'site-network' ] + ] + ]; // nginx configuration. $nginx['service_name'] = [ 'name' => 'nginx' ]; diff --git a/templates/docker-compose.mustache b/templates/docker-compose.mustache index 385a975d..f511c1c9 100644 --- a/templates/docker-compose.mustache +++ b/templates/docker-compose.mustache @@ -40,7 +40,7 @@ services: {{#networks}} networks: {{#net}} - - "{{name}}" + - {{name}} {{/net}} {{/networks}} {{/services}} From 6a7316ec6aa9da86abd8080911f40d148f2ee04e Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar Date: Fri, 24 Aug 2018 18:53:48 +0530 Subject: [PATCH 21/81] Fix nginx network Signed-off-by: Kirtan Gajjar --- src/Site_Docker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Site_Docker.php b/src/Site_Docker.php index 972e5156..fe5cfb2b 100644 --- a/src/Site_Docker.php +++ b/src/Site_Docker.php @@ -51,7 +51,7 @@ public function generate_docker_compose_yml( array $filters = [] ) { ]; $nginx['networks'] = [ 'net' => [ - $network_default, + [ 'name' => 'site-network' ], [ 'name' => 'global-network' ], ] ]; From a74c133e203fe7871ef63f76179dd8d06f36a9d1 Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar Date: Mon, 27 Aug 2018 18:29:44 +0530 Subject: [PATCH 22/81] Update docker-compose.yml and travis.yml Signed-off-by: Kirtan Gajjar --- .travis.yml | 8 +++++++- templates/docker-compose.mustache | 3 ++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2d954556..918eb470 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,8 @@ env: - TEST_COMMAND=$(echo $TRAVIS_REPO_SLUG | cut -d/ -f 2) # Get command name to be tested before_script: - - | + - sudo curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose + - | # Remove Xdebug for a huge performance increase: if [ -f ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini ]; then phpenv config-rm xdebug.ini @@ -33,3 +34,8 @@ notifications: email: on_success: never on_failure: change + +addons: + apt: + packages: + - docker-ce diff --git a/templates/docker-compose.mustache b/templates/docker-compose.mustache index f511c1c9..6b3c7268 100644 --- a/templates/docker-compose.mustache +++ b/templates/docker-compose.mustache @@ -1,4 +1,4 @@ -version: '3' +version: '3.5' services: @@ -48,6 +48,7 @@ services: {{#network}} networks: site-network: + name: ${VIRTUAL_HOST} global-network: external: name: ee-global-network From 6fbd6466d60ce86edfefa17ae7c80cae19bf5395 Mon Sep 17 00:00:00 2001 From: Thrijith Thankachan Date: Mon, 27 Aug 2018 19:55:28 +0530 Subject: [PATCH 23/81] Add vendor label in site-network --- src/Site_Docker.php | 8 +++++++- templates/docker-compose.mustache | 6 ++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Site_Docker.php b/src/Site_Docker.php index fe5cfb2b..0f929d03 100644 --- a/src/Site_Docker.php +++ b/src/Site_Docker.php @@ -60,7 +60,13 @@ public function generate_docker_compose_yml( array $filters = [] ) { $binding = [ 'services' => $base, - 'network' => true, + 'network' => [ + 'networks_labels' => [ + 'label' => [ + 'name' => 'org.label-schema.vendor=EasyEngine', + ], + ], + ], ]; $docker_compose_yml = mustache_render( SITE_TEMPLATE_ROOT . '/docker-compose.mustache', $binding ); diff --git a/templates/docker-compose.mustache b/templates/docker-compose.mustache index f511c1c9..c0468d45 100644 --- a/templates/docker-compose.mustache +++ b/templates/docker-compose.mustache @@ -48,6 +48,12 @@ services: {{#network}} networks: site-network: + {{#networks_labels}} + labels: + {{#label}} + - "{{name}}" + {{/label}} + {{/networks_labels}} global-network: external: name: ee-global-network From 6cac3c1e8567bc4d9857d3e7d01252e74a49d503 Mon Sep 17 00:00:00 2001 From: Thrijith Thankachan Date: Mon, 27 Aug 2018 20:22:47 +0530 Subject: [PATCH 24/81] Add site specfic label --- src/Site_Docker.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Site_Docker.php b/src/Site_Docker.php index 0f929d03..d063f034 100644 --- a/src/Site_Docker.php +++ b/src/Site_Docker.php @@ -63,7 +63,8 @@ public function generate_docker_compose_yml( array $filters = [] ) { 'network' => [ 'networks_labels' => [ 'label' => [ - 'name' => 'org.label-schema.vendor=EasyEngine', + [ 'name' => 'org.label-schema.vendor=EasyEngine' ], + [ 'name' => 'io.easyengine.site=${VIRTUAL_HOST}' ], ], ], ], From bc2f19357b4d0e4560e0479315e8aa97a275f6b5 Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar Date: Tue, 28 Aug 2018 09:51:17 +0530 Subject: [PATCH 25/81] trigger travis build From 9030635596f016f4522d34bd97b34ee6450f9b47 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Tue, 28 Aug 2018 15:34:54 +0530 Subject: [PATCH 26/81] Move AcmePhp from core to site-command Signed-off-by: Riddhesh Sanghvi --- .../Cli/Exception/AcmeCliActionException.php | 23 + AcmePhp/Cli/Exception/AcmeCliException.php | 23 + .../Exception/AcmeDnsResolutionException.php | 23 + .../Cli/Exception/CommandFlowException.php | 55 +++ AcmePhp/Cli/Repository/Repository.php | 439 ++++++++++++++++++ .../Cli/Repository/RepositoryInterface.php | 198 ++++++++ .../Cli/Repository/RepositoryV2Interface.php | 51 ++ AcmePhp/Cli/Serializer/PemEncoder.php | 55 +++ AcmePhp/Cli/Serializer/PemNormalizer.php | 55 +++ 9 files changed, 922 insertions(+) create mode 100644 AcmePhp/Cli/Exception/AcmeCliActionException.php create mode 100644 AcmePhp/Cli/Exception/AcmeCliException.php create mode 100644 AcmePhp/Cli/Exception/AcmeDnsResolutionException.php create mode 100644 AcmePhp/Cli/Exception/CommandFlowException.php create mode 100644 AcmePhp/Cli/Repository/Repository.php create mode 100644 AcmePhp/Cli/Repository/RepositoryInterface.php create mode 100644 AcmePhp/Cli/Repository/RepositoryV2Interface.php create mode 100644 AcmePhp/Cli/Serializer/PemEncoder.php create mode 100644 AcmePhp/Cli/Serializer/PemNormalizer.php diff --git a/AcmePhp/Cli/Exception/AcmeCliActionException.php b/AcmePhp/Cli/Exception/AcmeCliActionException.php new file mode 100644 index 00000000..a18f3e6f --- /dev/null +++ b/AcmePhp/Cli/Exception/AcmeCliActionException.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace AcmePhp\Cli\Exception; + +/** + * @author Titouan Galopin + */ +class AcmeCliActionException extends AcmeCliException +{ + public function __construct($actionName, \Exception $previous = null) + { + parent::__construct(sprintf('An exception was thrown during action "%s"', $actionName), $previous); + } +} diff --git a/AcmePhp/Cli/Exception/AcmeCliException.php b/AcmePhp/Cli/Exception/AcmeCliException.php new file mode 100644 index 00000000..b5f4c0c7 --- /dev/null +++ b/AcmePhp/Cli/Exception/AcmeCliException.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace AcmePhp\Cli\Exception; + +/** + * @author Titouan Galopin + */ +class AcmeCliException extends \RuntimeException +{ + public function __construct($message, \Exception $previous = null) + { + parent::__construct($message, 0, $previous); + } +} diff --git a/AcmePhp/Cli/Exception/AcmeDnsResolutionException.php b/AcmePhp/Cli/Exception/AcmeDnsResolutionException.php new file mode 100644 index 00000000..a1137999 --- /dev/null +++ b/AcmePhp/Cli/Exception/AcmeDnsResolutionException.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace AcmePhp\Cli\Exception; + +/** + * @author Jérémy Derussé + */ +class AcmeDnsResolutionException extends AcmeCliException +{ + public function __construct($message, \Exception $previous = null) + { + parent::__construct(null === $message ? 'An exception was thrown during resolution of DNS' : $message, $previous); + } +} diff --git a/AcmePhp/Cli/Exception/CommandFlowException.php b/AcmePhp/Cli/Exception/CommandFlowException.php new file mode 100644 index 00000000..f03b5b29 --- /dev/null +++ b/AcmePhp/Cli/Exception/CommandFlowException.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace AcmePhp\Cli\Exception; + +/** + * @author Jérémy Derussé + */ +class CommandFlowException extends AcmeCliException +{ + /** + * @var string + */ + private $missing; + /** + * @var string + */ + private $command; + /** + * @var array + */ + private $arguments; + + /** + * @param string $missing Missing requirement to fix the flow + * @param string $command Name of the command to run in order to fix the flow + * @param array $arguments Optional list of missing arguments + * @param \Exception|null $previous + */ + public function __construct($missing, $command, array $arguments = [], \Exception $previous = null) + { + $this->missing = $missing; + $this->command = $command; + $this->arguments = $arguments; + + $message = trim(sprintf( + 'You have to %s first. Run the command%sphp %s %s %s', + $missing, + PHP_EOL.PHP_EOL, + $_SERVER['PHP_SELF'], + $command, + implode(' ', $arguments) + )); + + parent::__construct($message, $previous); + } +} diff --git a/AcmePhp/Cli/Repository/Repository.php b/AcmePhp/Cli/Repository/Repository.php new file mode 100644 index 00000000..29a54c18 --- /dev/null +++ b/AcmePhp/Cli/Repository/Repository.php @@ -0,0 +1,439 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace AcmePhp\Cli\Repository; + +use AcmePhp\Cli\Exception\AcmeCliException; +use AcmePhp\Cli\Serializer\PemEncoder; +use AcmePhp\Core\Protocol\AuthorizationChallenge; +use AcmePhp\Core\Protocol\CertificateOrder; +use AcmePhp\Ssl\Certificate; +use AcmePhp\Ssl\CertificateResponse; +use AcmePhp\Ssl\DistinguishedName; +use AcmePhp\Ssl\KeyPair; +use AcmePhp\Ssl\PrivateKey; +use AcmePhp\Ssl\PublicKey; +use League\Flysystem\FilesystemInterface; +use Symfony\Component\Serializer\Encoder\JsonEncoder; +use Symfony\Component\Serializer\SerializerInterface; + +/** + * @author Titouan Galopin + */ +class Repository implements RepositoryV2Interface +{ + const PATH_ACCOUNT_KEY_PRIVATE = 'account/key.private.pem'; + const PATH_ACCOUNT_KEY_PUBLIC = 'account/key.public.pem'; + + const PATH_DOMAIN_KEY_PUBLIC = 'certs/{domain}/private/key.public.pem'; + const PATH_DOMAIN_KEY_PRIVATE = 'certs/{domain}/private/key.private.pem'; + const PATH_DOMAIN_CERT_CERT = 'certs/{domain}/public/cert.pem'; + const PATH_DOMAIN_CERT_CHAIN = 'certs/{domain}/public/chain.pem'; + const PATH_DOMAIN_CERT_FULLCHAIN = 'certs/{domain}/public/fullchain.pem'; + const PATH_DOMAIN_CERT_COMBINED = 'certs/{domain}/private/combined.pem'; + + const PATH_CACHE_AUTHORIZATION_CHALLENGE = 'var/{domain}/authorization_challenge.json'; + const PATH_CACHE_DISTINGUISHED_NAME = 'var/{domain}/distinguished_name.json'; + const PATH_CACHE_CERTIFICATE_ORDER = 'var/{domains}/certificate_order.json'; + + /** + * @var SerializerInterface + */ + private $serializer; + + /** + * @var FilesystemInterface + */ + private $master; + + /** + * @var FilesystemInterface + */ + private $backup; + + /** + * @var bool + */ + private $enableBackup; + + /** + * @param SerializerInterface $serializer + * @param FilesystemInterface $master + * @param FilesystemInterface $backup + * @param bool $enableBackup + */ + public function __construct(SerializerInterface $serializer, FilesystemInterface $master, FilesystemInterface $backup, $enableBackup) + { + $this->serializer = $serializer; + $this->master = $master; + $this->backup = $backup; + $this->enableBackup = $enableBackup; + } + + /** + * {@inheritdoc} + */ + public function storeCertificateResponse(CertificateResponse $certificateResponse) + { + $distinguishedName = $certificateResponse->getCertificateRequest()->getDistinguishedName(); + $domain = $distinguishedName->getCommonName(); + + $this->storeDomainKeyPair($domain, $certificateResponse->getCertificateRequest()->getKeyPair()); + $this->storeDomainDistinguishedName($domain, $distinguishedName); + $this->storeDomainCertificate($domain, $certificateResponse->getCertificate()); + } + + /** + * {@inheritdoc} + */ + public function storeAccountKeyPair(KeyPair $keyPair) + { + try { + $this->save( + self::PATH_ACCOUNT_KEY_PUBLIC, + $this->serializer->serialize($keyPair->getPublicKey(), PemEncoder::FORMAT) + ); + + $this->save( + self::PATH_ACCOUNT_KEY_PRIVATE, + $this->serializer->serialize($keyPair->getPrivateKey(), PemEncoder::FORMAT) + ); + } catch (\Exception $e) { + throw new AcmeCliException('Storing of account key pair failed', $e); + } + } + + private function getPathForDomain($path, $domain) + { + return strtr($path, ['{domain}' => $this->normalizeDomain($domain)]); + } + + private function getPathForDomainList($path, array $domains) + { + return strtr($path, ['{domains}' => $this->normalizeDomainList($domains)]); + } + + /** + * {@inheritdoc} + */ + public function hasAccountKeyPair() + { + return $this->master->has(self::PATH_ACCOUNT_KEY_PRIVATE); + } + + /** + * {@inheritdoc} + */ + public function loadAccountKeyPair() + { + try { + $publicKeyPem = $this->master->read(self::PATH_ACCOUNT_KEY_PUBLIC); + $privateKeyPem = $this->master->read(self::PATH_ACCOUNT_KEY_PRIVATE); + + return new KeyPair( + $this->serializer->deserialize($publicKeyPem, PublicKey::class, PemEncoder::FORMAT), + $this->serializer->deserialize($privateKeyPem, PrivateKey::class, PemEncoder::FORMAT) + ); + } catch (\Exception $e) { + throw new AcmeCliException('Loading of account key pair failed', $e); + } + } + + /** + * {@inheritdoc} + */ + public function storeDomainKeyPair($domain, KeyPair $keyPair) + { + try { + $this->save( + $this->getPathForDomain(self::PATH_DOMAIN_KEY_PUBLIC, $domain), + $this->serializer->serialize($keyPair->getPublicKey(), PemEncoder::FORMAT) + ); + + $this->save( + $this->getPathForDomain(self::PATH_DOMAIN_KEY_PRIVATE, $domain), + $this->serializer->serialize($keyPair->getPrivateKey(), PemEncoder::FORMAT) + ); + } catch (\Exception $e) { + throw new AcmeCliException(sprintf('Storing of domain %s key pair failed', $domain), $e); + } + } + + /** + * {@inheritdoc} + */ + public function hasDomainKeyPair($domain) + { + return $this->master->has($this->getPathForDomain(self::PATH_DOMAIN_KEY_PRIVATE, $domain)); + } + + /** + * {@inheritdoc} + */ + public function loadDomainKeyPair($domain) + { + try { + $publicKeyPem = $this->master->read($this->getPathForDomain(self::PATH_DOMAIN_KEY_PUBLIC, $domain)); + $privateKeyPem = $this->master->read($this->getPathForDomain(self::PATH_DOMAIN_KEY_PRIVATE, $domain)); + + return new KeyPair( + $this->serializer->deserialize($publicKeyPem, PublicKey::class, PemEncoder::FORMAT), + $this->serializer->deserialize($privateKeyPem, PrivateKey::class, PemEncoder::FORMAT) + ); + } catch (\Exception $e) { + throw new AcmeCliException(sprintf('Loading of domain %s key pair failed', $domain), $e); + } + } + + /** + * {@inheritdoc} + */ + public function storeDomainAuthorizationChallenge($domain, AuthorizationChallenge $authorizationChallenge) + { + try { + $this->save( + $this->getPathForDomain(self::PATH_CACHE_AUTHORIZATION_CHALLENGE, $domain), + $this->serializer->serialize($authorizationChallenge, JsonEncoder::FORMAT) + ); + } catch (\Exception $e) { + throw new AcmeCliException(sprintf('Storing of domain %s authorization challenge failed', $domain), $e); + } + } + + /** + * {@inheritdoc} + */ + public function hasDomainAuthorizationChallenge($domain) + { + return $this->master->has($this->getPathForDomain(self::PATH_CACHE_AUTHORIZATION_CHALLENGE, $domain)); + } + + /** + * {@inheritdoc} + */ + public function loadDomainAuthorizationChallenge($domain) + { + try { + $json = $this->master->read($this->getPathForDomain(self::PATH_CACHE_AUTHORIZATION_CHALLENGE, $domain)); + + return $this->serializer->deserialize($json, AuthorizationChallenge::class, JsonEncoder::FORMAT); + } catch (\Exception $e) { + throw new AcmeCliException(sprintf('Loading of domain %s authorization challenge failed', $domain), $e); + } + } + + /** + * {@inheritdoc} + */ + public function storeDomainDistinguishedName($domain, DistinguishedName $distinguishedName) + { + try { + $this->save( + $this->getPathForDomain(self::PATH_CACHE_DISTINGUISHED_NAME, $domain), + $this->serializer->serialize($distinguishedName, JsonEncoder::FORMAT) + ); + } catch (\Exception $e) { + throw new AcmeCliException(sprintf('Storing of domain %s distinguished name failed', $domain), $e); + } + } + + /** + * {@inheritdoc} + */ + public function hasDomainDistinguishedName($domain) + { + return $this->master->has($this->getPathForDomain(self::PATH_CACHE_DISTINGUISHED_NAME, $domain)); + } + + /** + * {@inheritdoc} + */ + public function loadDomainDistinguishedName($domain) + { + try { + $json = $this->master->read($this->getPathForDomain(self::PATH_CACHE_DISTINGUISHED_NAME, $domain)); + + return $this->serializer->deserialize($json, DistinguishedName::class, JsonEncoder::FORMAT); + } catch (\Exception $e) { + throw new AcmeCliException(sprintf('Loading of domain %s distinguished name failed', $domain), $e); + } + } + + /** + * {@inheritdoc} + */ + public function storeDomainCertificate($domain, Certificate $certificate) + { + // Simple certificate + $certPem = $this->serializer->serialize($certificate, PemEncoder::FORMAT); + + // Issuer chain + $issuerChain = []; + $issuerCertificate = $certificate->getIssuerCertificate(); + + while (null !== $issuerCertificate) { + $issuerChain[] = $this->serializer->serialize($issuerCertificate, PemEncoder::FORMAT); + $issuerCertificate = $issuerCertificate->getIssuerCertificate(); + } + + $chainPem = implode("\n", $issuerChain); + + // Full chain + $fullChainPem = $certPem.$chainPem; + + // Combined + $keyPair = $this->loadDomainKeyPair($domain); + $combinedPem = $fullChainPem.$this->serializer->serialize($keyPair->getPrivateKey(), PemEncoder::FORMAT); + + // Save + $this->save($this->getPathForDomain(self::PATH_DOMAIN_CERT_CERT, $domain), $certPem); + $this->save($this->getPathForDomain(self::PATH_DOMAIN_CERT_CHAIN, $domain), $chainPem); + $this->save($this->getPathForDomain(self::PATH_DOMAIN_CERT_FULLCHAIN, $domain), $fullChainPem); + $this->save($this->getPathForDomain(self::PATH_DOMAIN_CERT_COMBINED, $domain), $combinedPem); + } + + /** + * {@inheritdoc} + */ + public function hasDomainCertificate($domain) + { + return $this->master->has($this->getPathForDomain(self::PATH_DOMAIN_CERT_FULLCHAIN, $domain)); + } + + /** + * {@inheritdoc} + */ + public function loadDomainCertificate($domain) + { + try { + $pems = explode('-----BEGIN CERTIFICATE-----', $this->master->read($this->getPathForDomain(self::PATH_DOMAIN_CERT_FULLCHAIN, $domain))); + } catch (\Exception $e) { + throw new AcmeCliException(sprintf('Loading of domain %s certificate failed', $domain), $e); + } + + $pems = array_map(function ($item) { + return trim(str_replace('-----END CERTIFICATE-----', '', $item)); + }, $pems); + array_shift($pems); + $pems = array_reverse($pems); + + $certificate = null; + + foreach ($pems as $pem) { + $certificate = new Certificate( + "-----BEGIN CERTIFICATE-----\n".$pem."\n-----END CERTIFICATE-----", + $certificate + ); + } + + return $certificate; + } + + /** + * {@inheritdoc} + */ + public function storeCertificateOrder(array $domains, CertificateOrder $order) + { + try { + $this->save( + $this->getPathForDomainList(self::PATH_CACHE_CERTIFICATE_ORDER, $domains), + $this->serializer->serialize($order, JsonEncoder::FORMAT) + ); + } catch (\Exception $e) { + throw new AcmeCliException(sprintf('Storing of domains %s certificate order failed', implode(', ', $domains)), $e); + } + } + + /** + * {@inheritdoc} + */ + public function hasCertificateOrder(array $domains) + { + return $this->master->has($this->getPathForDomainList(self::PATH_CACHE_CERTIFICATE_ORDER, $domains)); + } + + /** + * {@inheritdoc} + */ + public function loadCertificateOrder(array $domains) + { + try { + $json = $this->master->read($this->getPathForDomainList(self::PATH_CACHE_CERTIFICATE_ORDER, $domains)); + + return $this->serializer->deserialize($json, CertificateOrder::class, JsonEncoder::FORMAT); + } catch (\Exception $e) { + throw new AcmeCliException(sprintf('Loading of domains %s certificate order failed', implode(', ', $domains)), $e); + } + } + + /** + * {@inheritdoc} + */ + public function save($path, $content, $visibility = self::VISIBILITY_PRIVATE) + { + if (!$this->master->has($path)) { + // File creation: remove from backup if it existed and warm-up both master and backup + $this->createAndBackup($path, $content); + } else { + // File update: backup before writing + $this->backupAndUpdate($path, $content); + } + + if ($this->enableBackup) { + $this->backup->setVisibility($path, $visibility); + } + + $this->master->setVisibility($path, $visibility); + } + + private function createAndBackup($path, $content) + { + if ($this->enableBackup) { + if ($this->backup->has($path)) { + $this->backup->delete($path); + } + + $this->backup->write($path, $content); + } + + $this->master->write($path, $content); + } + + private function backupAndUpdate($path, $content) + { + if ($this->enableBackup) { + $oldContent = $this->master->read($path); + + if (false !== $oldContent) { + if ($this->backup->has($path)) { + $this->backup->update($path, $oldContent); + } else { + $this->backup->write($path, $oldContent); + } + } + } + + $this->master->update($path, $content); + } + + private function normalizeDomain($domain) + { + return $domain; + } + + private function normalizeDomainList(array $domains) + { + $normalizedDomains = array_unique(array_map([$this, 'normalizeDomain'], $domains)); + sort($normalizedDomains); + + return (isset($domains[0]) ? $this->normalizeDomain($domains[0]) : '-').'/'.sha1(json_encode($normalizedDomains)); + } +} diff --git a/AcmePhp/Cli/Repository/RepositoryInterface.php b/AcmePhp/Cli/Repository/RepositoryInterface.php new file mode 100644 index 00000000..f42c5277 --- /dev/null +++ b/AcmePhp/Cli/Repository/RepositoryInterface.php @@ -0,0 +1,198 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace AcmePhp\Cli\Repository; + +use AcmePhp\Cli\Exception\AcmeCliException; +use AcmePhp\Core\Protocol\AuthorizationChallenge; +use AcmePhp\Ssl\Certificate; +use AcmePhp\Ssl\CertificateResponse; +use AcmePhp\Ssl\DistinguishedName; +use AcmePhp\Ssl\KeyPair; + +/** + * @author Titouan Galopin + */ +interface RepositoryInterface +{ + const VISIBILITY_PUBLIC = 'public'; + const VISIBILITY_PRIVATE = 'private'; + + /** + * Extract important elements from the given certificate response and store them + * in the repository. + * + * This method will use the distinguished name common name as a domain to store: + * - the key pair + * - the certificate request + * - the certificate + * + * @param CertificateResponse $certificateResponse + * + * @throws AcmeCliException + */ + public function storeCertificateResponse(CertificateResponse $certificateResponse); + + /** + * Store a given key pair as the account key pair (the global key pair used to + * interact with the ACME server). + * + * @param KeyPair $keyPair + * + * @throws AcmeCliException + */ + public function storeAccountKeyPair(KeyPair $keyPair); + + /** + * Check if there is an account key pair in the repository. + * + * @return bool + */ + public function hasAccountKeyPair(); + + /** + * Load the account key pair. + * + * @throws AcmeCliException + * + * @return KeyPair + */ + public function loadAccountKeyPair(); + + /** + * Store a given key pair as associated to a given domain. + * + * @param string $domain + * @param KeyPair $keyPair + * + * @throws AcmeCliException + */ + public function storeDomainKeyPair($domain, KeyPair $keyPair); + + /** + * Check if there is a key pair associated to the given domain in the repository. + * + * @param string $domain + * + * @return bool + */ + public function hasDomainKeyPair($domain); + + /** + * Load the key pair associated to a given domain. + * + * @param string $domain + * + * @throws AcmeCliException + * + * @return KeyPair + */ + public function loadDomainKeyPair($domain); + + /** + * Store a given authorization challenge as associated to a given domain. + * + * @param string $domain + * @param AuthorizationChallenge $authorizationChallenge + * + * @throws AcmeCliException + */ + public function storeDomainAuthorizationChallenge($domain, AuthorizationChallenge $authorizationChallenge); + + /** + * Check if there is an authorization challenge associated to the given domain in the repository. + * + * @param string $domain + * + * @return bool + */ + public function hasDomainAuthorizationChallenge($domain); + + /** + * Load the authorization challenge associated to a given domain. + * + * @param string $domain + * + * @throws AcmeCliException + * + * @return AuthorizationChallenge + */ + public function loadDomainAuthorizationChallenge($domain); + + /** + * Store a given distinguished name as associated to a given domain. + * + * @param string $domain + * @param DistinguishedName $distinguishedName + * + * @throws AcmeCliException + */ + public function storeDomainDistinguishedName($domain, DistinguishedName $distinguishedName); + + /** + * Check if there is a distinguished name associated to the given domain in the repository. + * + * @param string $domain + * + * @return bool + */ + public function hasDomainDistinguishedName($domain); + + /** + * Load the distinguished name associated to a given domain. + * + * @param string $domain + * + * @throws AcmeCliException + * + * @return DistinguishedName + */ + public function loadDomainDistinguishedName($domain); + + /** + * Store a given certificate as associated to a given domain. + * + * @param string $domain + * @param Certificate $certificate + * + * @throws AcmeCliException + */ + public function storeDomainCertificate($domain, Certificate $certificate); + + /** + * Check if there is a certificate associated to the given domain in the repository. + * + * @param string $domain + * + * @return bool + */ + public function hasDomainCertificate($domain); + + /** + * Load the certificate associated to a given domain. + * + * @param string $domain + * + * @throws AcmeCliException + * + * @return Certificate + */ + public function loadDomainCertificate($domain); + + /** + * Save a given string into a given path handling backup. + * + * @param string $path + * @param string $content + * @param string $visibility the visibilty to use for this file + */ + public function save($path, $content, $visibility = self::VISIBILITY_PRIVATE); +} diff --git a/AcmePhp/Cli/Repository/RepositoryV2Interface.php b/AcmePhp/Cli/Repository/RepositoryV2Interface.php new file mode 100644 index 00000000..f3b67e03 --- /dev/null +++ b/AcmePhp/Cli/Repository/RepositoryV2Interface.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace AcmePhp\Cli\Repository; + +use AcmePhp\Cli\Exception\AcmeCliException; +use AcmePhp\Core\Protocol\CertificateOrder; + +/** + * @author Titouan Galopin + */ +interface RepositoryV2Interface extends RepositoryInterface +{ + /** + * Store a given certificate as associated to a given domain. + * + * @param array $domains + * @param CertificateOrder $order + * + * @throws AcmeCliException + */ + public function storeCertificateOrder(array $domains, CertificateOrder $order); + + /** + * Check if there is a certificate associated to the given domain in the repository. + * + * @param string $domain + * + * @return bool + */ + public function hasCertificateOrder(array $domains); + + /** + * Load the certificate associated to a given domain. + * + * @param string $domain + * + * @throws AcmeCliException + * + * @return CertificateOrder + */ + public function loadCertificateOrder(array $domains); +} diff --git a/AcmePhp/Cli/Serializer/PemEncoder.php b/AcmePhp/Cli/Serializer/PemEncoder.php new file mode 100644 index 00000000..01d3a15d --- /dev/null +++ b/AcmePhp/Cli/Serializer/PemEncoder.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace AcmePhp\Cli\Serializer; + +use Symfony\Component\Serializer\Encoder\DecoderInterface; +use Symfony\Component\Serializer\Encoder\EncoderInterface; + +/** + * @author Titouan Galopin + */ +class PemEncoder implements EncoderInterface, DecoderInterface +{ + const FORMAT = 'pem'; + + /** + * {@inheritdoc} + */ + public function encode($data, $format, array $context = []) + { + return trim($data)."\n"; + } + + /** + * {@inheritdoc} + */ + public function decode($data, $format, array $context = []) + { + return trim($data)."\n"; + } + + /** + * {@inheritdoc} + */ + public function supportsEncoding($format) + { + return self::FORMAT === $format; + } + + /** + * {@inheritdoc} + */ + public function supportsDecoding($format) + { + return self::FORMAT === $format; + } +} diff --git a/AcmePhp/Cli/Serializer/PemNormalizer.php b/AcmePhp/Cli/Serializer/PemNormalizer.php new file mode 100644 index 00000000..564f1b93 --- /dev/null +++ b/AcmePhp/Cli/Serializer/PemNormalizer.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace AcmePhp\Cli\Serializer; + +use AcmePhp\Ssl\Certificate; +use AcmePhp\Ssl\Key; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; + +/** + * @author Titouan Galopin + */ +class PemNormalizer implements NormalizerInterface, DenormalizerInterface +{ + /** + * {@inheritdoc} + */ + public function normalize($object, $format = null, array $context = []) + { + return $object->getPEM(); + } + + /** + * {@inheritdoc} + */ + public function denormalize($data, $class, $format = null, array $context = []) + { + return new $class($data); + } + + /** + * {@inheritdoc} + */ + public function supportsNormalization($data, $format = null) + { + return is_object($data) && ($data instanceof Certificate || $data instanceof Key); + } + + /** + * {@inheritdoc} + */ + public function supportsDenormalization($data, $type, $format = null) + { + return is_string($data); + } +} From 9dcdd842f40f63fe40ac00f2590c38efe38da971 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Tue, 28 Aug 2018 15:35:31 +0530 Subject: [PATCH 27/81] Move site related files from core to site-command Signed-off-by: Riddhesh Sanghvi --- src/Shutdown_Handler.php | 19 ++ src/Site_Letsencrypt.php | 530 ++++++++++++++++++++++++++++++++++++++ src/class-ee-site.php | 539 +++++++++++++++++++++++++++++++++++++++ src/site-utils.php | 370 +++++++++++++++++++++++++++ 4 files changed, 1458 insertions(+) create mode 100644 src/Shutdown_Handler.php create mode 100644 src/Site_Letsencrypt.php create mode 100644 src/class-ee-site.php create mode 100644 src/site-utils.php diff --git a/src/Shutdown_Handler.php b/src/Shutdown_Handler.php new file mode 100644 index 00000000..2df3c30e --- /dev/null +++ b/src/Shutdown_Handler.php @@ -0,0 +1,19 @@ +getMethod( 'shutDownFunction' ); + $method->setAccessible( true ); + $method->invoke( $site_command[0] ); + } +} diff --git a/src/Site_Letsencrypt.php b/src/Site_Letsencrypt.php new file mode 100644 index 00000000..9c396b94 --- /dev/null +++ b/src/Site_Letsencrypt.php @@ -0,0 +1,530 @@ +conf_dir = EE_CONF_ROOT . '/acme-conf'; + $this->setRepository(); + $this->setAcmeClient(); + } + + private function setAcmeClient() { + + if ( ! $this->repository->hasAccountKeyPair() ) { + EE::debug( 'No account key pair was found, generating one.' ); + EE::debug( 'Generating a key pair' ); + + $keygen = new KeyPairGenerator(); + $accountKeyPair = $keygen->generateKeyPair(); + EE::debug( 'Key pair generated, storing' ); + $this->repository->storeAccountKeyPair( $accountKeyPair ); + } else { + EE::debug( 'Loading account keypair' ); + $accountKeyPair = $this->repository->loadAccountKeyPair(); + } + + $this->accountKeyPair ?? $this->accountKeyPair = $accountKeyPair; + + $secureHttpClient = $this->getSecureHttpClient(); + $csrSigner = new CertificateRequestSigner(); + + $this->client = new AcmeClient( $secureHttpClient, 'https://acme-v02.api.letsencrypt.org/directory', $csrSigner ); + + } + + private function setRepository( $enable_backup = false ) { + $this->serializer ?? $this->serializer = new Serializer( + [ new PemNormalizer(), new GetSetMethodNormalizer() ], + [ new PemEncoder(), new JsonEncoder() ] + ); + $this->master ?? $this->master = new Filesystem( new Local( $this->conf_dir ) ); + $this->backup ?? $this->backup = new Filesystem( new NullAdapter() ); + + $this->repository = new Repository( $this->serializer, $this->master, $this->backup, $enable_backup ); + } + + private function getSecureHttpClient() { + $this->httpClient ?? $this->httpClient = new Client(); + $this->base64SafeEncoder ?? $this->base64SafeEncoder = new Base64SafeEncoder(); + $this->keyParser ?? $this->keyParser = new KeyParser(); + $this->dataSigner ?? $this->dataSigner = new DataSigner(); + $this->serverErrorHandler ?? $this->serverErrorHandler = new ServerErrorHandler(); + + return new SecureHttpClient( + $this->accountKeyPair, + $this->httpClient, + $this->base64SafeEncoder, + $this->keyParser, + $this->dataSigner, + $this->serverErrorHandler + ); + } + + + public function register( $email ) { + try { + $this->client->registerAccount( null, $email ); + } + catch ( Exception $e ) { + EE::warning( $e->getMessage() ); + EE::warning( 'It seems you\'re in local environment or there is some issue with network, please check logs. Skipping letsencrypt.' ); + + return false; + } + EE::debug( "Account with email id: $email registered successfully!" ); + return true; + } + + public function authorize( Array $domains, $site_root, $wildcard = false ) { + $solver = $wildcard ? new SimpleDnsSolver( null, new ConsoleOutput() ) : new SimpleHttpSolver(); + $solverName = $wildcard ? 'dns-01' : 'http-01'; + try { + $order = $this->client->requestOrder( $domains ); + } + catch ( Exception $e ) { + EE::warning( $e->getMessage() ); + EE::warning( 'It seems you\'re in local environment or using non-public domain, please check logs. Skipping letsencrypt.' ); + + return false; + } + + $authorizationChallengesToSolve = []; + foreach ( $order->getAuthorizationsChallenges() as $domainKey => $authorizationChallenges ) { + $authorizationChallenge = null; + foreach ( $authorizationChallenges as $candidate ) { + if ( $solver->supports( $candidate ) ) { + $authorizationChallenge = $candidate; + EE::debug( 'Authorization challenge supported by solver. Solver: ' . $solverName . ' Challenge: ' . $candidate->getType() ); + break; + } + // Should not get here as we are handling it. + EE::debug( 'Authorization challenge not supported by solver. Solver: ' . $solverName . ' Challenge: ' . $candidate->getType() ); + } + if ( null === $authorizationChallenge ) { + throw new ChallengeNotSupportedException(); + } + EE::debug( 'Storing authorization challenge. Domain: ' . $domainKey . ' Challenge: ' . print_r( $authorizationChallenge->toArray(), true ) ); + + $this->repository->storeDomainAuthorizationChallenge( $domainKey, $authorizationChallenge ); + $authorizationChallengesToSolve[] = $authorizationChallenge; + } + + /** @var AuthorizationChallenge $authorizationChallenge */ + foreach ( $authorizationChallengesToSolve as $authorizationChallenge ) { + EE::debug( 'Solving authorization challenge: Domain: ' . $authorizationChallenge->getDomain() . ' Challenge: ' . print_r( $authorizationChallenge->toArray(), true ) ); + $solver->solve( $authorizationChallenge ); + + if ( ! $wildcard ) { + $token = $authorizationChallenge->toArray()['token']; + $payload = $authorizationChallenge->toArray()['payload']; + EE::launch( "mkdir -p $site_root/app/src/.well-known/acme-challenge/" ); + EE::debug( "Creating challange file $site_root/app/src/.well-known/acme-challenge/$token" ); + file_put_contents( "$site_root/app/src/.well-known/acme-challenge/$token", $payload ); + EE::launch( "chown www-data: $site_root/app/src/.well-known/acme-challenge/$token" ); + } + } + + $this->repository->storeCertificateOrder( $domains, $order ); + + return true; + } + + public function check( Array $domains, $wildcard = false ) { + EE::debug( ('Starting check with solver ') . ($wildcard ? 'dns' : 'http') ); + $solver = $wildcard ? new SimpleDnsSolver( null, new ConsoleOutput() ) : new SimpleHttpSolver(); + $validator = new ChainValidator( + [ + new WaitingValidator( new HttpValidator() ), + new WaitingValidator( new DnsValidator() ) + ] + ); + + $order = null; + if ( $this->repository->hasCertificateOrder( $domains ) ) { + $order = $this->repository->loadCertificateOrder( $domains ); + EE::debug( sprintf( 'Loading the authorization token for domains %s ...', implode( ', ', $domains ) ) ); + } + + $authorizationChallengeToCleanup = []; + foreach ( $domains as $domain ) { + if ( $order ) { + $authorizationChallenge = null; + $authorizationChallenges = $order->getAuthorizationChallenges( $domain ); + foreach ( $authorizationChallenges as $challenge ) { + if ( $solver->supports( $challenge ) ) { + $authorizationChallenge = $challenge; + break; + } + } + if ( null === $authorizationChallenge ) { + throw new ChallengeNotSupportedException(); + } + } else { + if ( ! $this->repository->hasDomainAuthorizationChallenge( $domain ) ) { + EE::error( "Domain: $domain not yet authorized/has not been started of with EasyEngine letsencrypt site creation." ); + } + $authorizationChallenge = $this->repository->loadDomainAuthorizationChallenge( $domain ); + if ( ! $solver->supports( $authorizationChallenge ) ) { + throw new ChallengeNotSupportedException(); + } + } + EE::debug( 'Challenge loaded.' ); + + $authorizationChallenge = $this->client->reloadAuthorization( $authorizationChallenge ); + if ( ! $authorizationChallenge->isValid() ) { + EE::debug( sprintf( 'Testing the challenge for domain %s', $domain ) ); + if ( ! $validator->isValid( $authorizationChallenge ) ) { + EE::warning( sprintf( 'Can not valid challenge for domain %s', $domain ) ); + } + + EE::debug( sprintf( 'Requesting authorization check for domain %s', $domain ) ); + try { + $this->client->challengeAuthorization( $authorizationChallenge ); + } + catch ( Exception $e ) { + EE::debug( $e->getMessage() ); + EE::warning( 'Challange Authorization failed. Check logs and check if your domain is pointed correctly to this server.' ); + $site_name = isset( $domains[1] ) ? $domains[1] : $domains[0]; + EE::log( "Re-run `ee site le $site_name` after fixing the issue." ); + + return false; + } + $authorizationChallengeToCleanup[] = $authorizationChallenge; + } + } + + EE::log( 'The authorization check was successful!' ); + + if ( $solver instanceof MultipleChallengesSolverInterface ) { + $solver->cleanupAll( $authorizationChallengeToCleanup ); + } else { + /** @var AuthorizationChallenge $authorizationChallenge */ + foreach ( $authorizationChallengeToCleanup as $authorizationChallenge ) { + $solver->cleanup( $authorizationChallenge ); + } + } + return true; + } + + public function request( $domain, $altNames = [], $email, $force=false ) { + $alternativeNames = array_unique( $altNames ); + sort( $alternativeNames ); + + // Certificate renewal + if ( $this->hasValidCertificate( $domain, $alternativeNames ) ) { + EE::debug( "Certificate found for $domain, executing renewal" ); + + return $this->executeRenewal( $domain, $alternativeNames, $force ); + } + + EE::debug( "No certificate found, executing first request for $domain" ); + + // Certificate first request + return $this->executeFirstRequest( $domain, $alternativeNames, $email ); + } + + /** + * Request a first certificate for the given domain. + * + * @param string $domain + * @param array $alternativeNames + */ + private function executeFirstRequest( $domain, array $alternativeNames, $email ) { + EE::log( 'Executing first request.' ); + + // Generate domain key pair + $keygen = new KeyPairGenerator(); + $domainKeyPair = $keygen->generateKeyPair(); + $this->repository->storeDomainKeyPair( $domain, $domainKeyPair ); + + EE::debug( "$domain Domain key pair generated and stored" ); + + $distinguishedName = $this->getOrCreateDistinguishedName( $domain, $alternativeNames, $email ); + // TODO: ask them ;) + EE::debug( 'Distinguished name informations have been stored locally for this domain (they won\'t be asked on renewal).' ); + + // Order + $domains = array_merge( [ $domain ], $alternativeNames ); + EE::debug( sprintf( 'Loading the order related to the domains %s .', implode( ', ', $domains ) ) ); + if ( ! $this->repository->hasCertificateOrder( $domains ) ) { + EE::error( "$domain has not yet been authorized." ); + } + $order = $this->repository->loadCertificateOrder( $domains ); + + // Request + EE::log( sprintf( 'Requesting first certificate for domain %s.', $domain ) ); + $csr = new CertificateRequest( $distinguishedName, $domainKeyPair ); + $response = $this->client->finalizeOrder( $order, $csr ); + EE::log( 'Certificate received' ); + + // Store + $this->repository->storeDomainCertificate( $domain, $response->getCertificate() ); + EE::log( 'Certificate stored' ); + + // Post-generate actions + $this->moveCertsToNginxProxy( $domain ); + } + + private function moveCertsToNginxProxy( string $domain ) { + + $key_source_file = strtr( $this->conf_dir . '/' . Repository::PATH_DOMAIN_KEY_PRIVATE, [ '{domain}' => $domain ] ); + $crt_source_file = strtr( $this->conf_dir . '/' . Repository::PATH_DOMAIN_CERT_FULLCHAIN, [ '{domain}' => $domain ] ); + $chain_source_file = strtr( $this->conf_dir . '/' . Repository::PATH_DOMAIN_CERT_CHAIN, [ '{domain}' => $domain ] ); + + $key_dest_file = EE_CONF_ROOT . '/nginx/certs/' . $domain . '.key'; + $crt_dest_file = EE_CONF_ROOT . '/nginx/certs/' . $domain . '.crt'; + $chain_dest_file = EE_CONF_ROOT . '/nginx/certs/' . $domain . '.chain.pem'; + + copy( $key_source_file, $key_dest_file ); + copy( $crt_source_file, $crt_dest_file ); + copy( $chain_source_file, $chain_dest_file ); + } + + /** + * Renew a given domain certificate. + * + * @param string $domain + * @param array $alternativeNames + * @param bool $force + */ + private function executeRenewal( $domain, array $alternativeNames, $force = false ) { + try { + // Check expiration date to avoid too much renewal + EE::log( "Loading current certificate for $domain" ); + + $certificate = $this->repository->loadDomainCertificate( $domain ); + + if ( ! $force ) { + $certificateParser = new CertificateParser(); + $parsedCertificate = $certificateParser->parse( $certificate ); + + if ( $parsedCertificate->getValidTo()->format( 'U' ) - time() >= 604800 ) { + + EE::log( + sprintf( + 'Current certificate is valid until %s, renewal is not necessary.', + $parsedCertificate->getValidTo()->format( 'Y-m-d H:i:s' ) + ) + ); + + return; + } + + EE::log( + sprintf( + 'Current certificate will expire in less than a week (%s), renewal is required.', + $parsedCertificate->getValidTo()->format( 'Y-m-d H:i:s' ) + ) + ); + } else { + EE::log( 'Forced renewal.' ); + } + + // Key pair + EE::debug( 'Loading domain key pair...' ); + $domainKeyPair = $this->repository->loadDomainKeyPair( $domain ); + + // Distinguished name + EE::debug( 'Loading domain distinguished name...' ); + $distinguishedName = $this->getOrCreateDistinguishedName( $domain, $alternativeNames ); + + // Order + $domains = array_merge( [ $domain ], $alternativeNames ); + EE::debug( sprintf( 'Loading the order related to the domains %s.', implode( ', ', $domains ) ) ); + if ( ! $this->repository->hasCertificateOrder( $domains ) ) { + EE::error( "$domain has not yet been authorized." ); + } + $order = $this->repository->loadCertificateOrder( $domains ); + + // Renewal + EE::log( sprintf( 'Renewing certificate for domain %s.', $domain ) ); + $csr = new CertificateRequest( $distinguishedName, $domainKeyPair ); + $response = $this->client->finalizeOrder( $order, $csr ); + EE::log( 'Certificate received' ); + + $this->repository->storeDomainCertificate( $domain, $response->getCertificate() ); + $this->log( 'Certificate stored' ); + + // Post-generate actions + $this->moveCertsToNginxProxy( $domain ); + EE::log( 'Certificate renewed successfully!' ); + + } + catch ( \Exception $e ) { + EE::warning( 'A critical error occured during certificate renewal' ); + EE::debug( print_r( $e, true ) ); + + throw $e; + } + catch ( \Throwable $e ) { + EE::warning( 'A critical error occured during certificate renewal' ); + EE::debug( print_r( $e, true ) ); + + throw $e; + } + } + + private function hasValidCertificate( $domain, array $alternativeNames ) { + if ( ! $this->repository->hasDomainCertificate( $domain ) ) { + return false; + } + + if ( ! $this->repository->hasDomainKeyPair( $domain ) ) { + return false; + } + + if ( ! $this->repository->hasDomainDistinguishedName( $domain ) ) { + return false; + } + + if ( $this->repository->loadDomainDistinguishedName( $domain )->getSubjectAlternativeNames() !== $alternativeNames ) { + return false; + } + + return true; + } + + /** + * Retrieve the stored distinguishedName or create a new one if needed. + * + * @param string $domain + * @param array $alternativeNames + * + * @return DistinguishedName + */ + private function getOrCreateDistinguishedName( $domain, array $alternativeNames, $email ) { + if ( $this->repository->hasDomainDistinguishedName( $domain ) ) { + $original = $this->repository->loadDomainDistinguishedName( $domain ); + + $distinguishedName = new DistinguishedName( + $domain, + $original->getCountryName(), + $original->getStateOrProvinceName(), + $original->getLocalityName(), + $original->getOrganizationName(), + $original->getOrganizationalUnitName(), + $original->getEmailAddress(), + $alternativeNames + ); + } else { + // Ask DistinguishedName + $distinguishedName = new DistinguishedName( + $domain, + // TODO: Ask and fill these values properly + 'US', + 'CA', + 'Mountain View', + 'Let\'s Encrypt', + 'Let\'s Encrypt Authority X3', + $email, + $alternativeNames + ); + + } + + $this->repository->storeDomainDistinguishedName( $domain, $distinguishedName ); + + return $distinguishedName; + } + + + public function status() { + $this->master ?? $this->master = new Filesystem( new Local( $this->conf_dir ) ); + + $certificateParser = new CertificateParser(); + + $table = new Table( $output ); + $table->setHeaders( [ 'Domain', 'Issuer', 'Valid from', 'Valid to', 'Needs renewal?' ] ); + + $directories = $this->master->listContents( 'certs' ); + + foreach ( $directories as $directory ) { + if ( 'dir' !== $directory['type'] ) { + continue; + } + + $parsedCertificate = $certificateParser->parse( $this->repository->loadDomainCertificate( $directory['basename'] ) ); + if ( ! $input->getOption( 'all' ) && $parsedCertificate->isExpired() ) { + continue; + } + $domainString = $parsedCertificate->getSubject(); + + $alternativeNames = array_diff( $parsedCertificate->getSubjectAlternativeNames(), [ $parsedCertificate->getSubject() ] ); + if ( count( $alternativeNames ) ) { + sort( $alternativeNames ); + $last = array_pop( $alternativeNames ); + foreach ( $alternativeNames as $alternativeName ) { + $domainString .= "\n ├── " . $alternativeName; + } + $domainString .= "\n └── " . $last; + } + + $table->addRow( + [ + $domainString, + $parsedCertificate->getIssuer(), + $parsedCertificate->getValidFrom()->format( 'Y-m-d H:i:s' ), + $parsedCertificate->getValidTo()->format( 'Y-m-d H:i:s' ), + ( $parsedCertificate->getValidTo()->format( 'U' ) - time() < 604800 ) ? 'Yes' : 'No', + ] + ); + } + + $table->render(); + } + + public function cleanup( $site_root ) { + $challange_dir = "$site_root/app/src/.well-known"; + if ( file_exists( "$site_root/app/src/.well-known" ) ) { + EE::debug( 'Cleaning up webroot files.' ); + EE\Utils\delete_dir( $challange_dir ); + } + } +} diff --git a/src/class-ee-site.php b/src/class-ee-site.php new file mode 100644 index 00000000..1dcbae7a --- /dev/null +++ b/src/class-ee-site.php @@ -0,0 +1,539 @@ +] + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - yaml + * - json + * - count + * - text + * --- + * + * @subcommand list + */ + public function _list( $args, $assoc_args ) { + + EE\Utils\delem_log( 'site list start' ); + $format = EE\Utils\get_flag_value( $assoc_args, 'format' ); + $enabled = EE\Utils\get_flag_value( $assoc_args, 'enabled' ); + $disabled = EE\Utils\get_flag_value( $assoc_args, 'disabled' ); + + $sites = Site::all(); + + if ( $enabled && ! $disabled ) { + $sites = Site::where( 'is_enabled', true ); + } elseif ( $disabled && ! $enabled ) { + $sites = Site::where( 'is_enabled', false ); + } + + if ( empty( $sites ) ) { + EE::error( 'No sites found!' ); + } + + if ( 'text' === $format ) { + foreach ( $sites as $site ) { + EE::log( $site->site_url ); + } + } else { + $result = array_map( + function ( $site ) { + $site->site = $site->site_url; + $site->status = $site->site_enabled ? 'enabled' : 'disabled'; + + return $site; + }, $sites + ); + + $formatter = new EE\Formatter( $assoc_args, [ 'site', 'status' ] ); + + $formatter->display_items( $result ); + } + + EE\Utils\delem_log( 'site list end' ); + } + + + /** + * Deletes a website. + * + * ## OPTIONS + * + * + * : Name of website to be deleted. + * + * [--yes] + * : Do not prompt for confirmation. + */ + public function delete( $args, $assoc_args ) { + + EE\Utils\delem_log( 'site delete start' ); + $this->populate_site_info( $args ); + EE::confirm( sprintf( 'Are you sure you want to delete %s?', $this->site['url'] ), $assoc_args ); + $this->delete_site( 5, $this->site['url'], $this->site['root'] ); + EE\Utils\delem_log( 'site delete end' ); + } + + /** + * Function to delete the given site. + * + * @param int $level Level of deletion. + * Level - 0: No need of clean-up. + * Level - 1: Clean-up only the site-root. + * Level - 2: Try to remove network. The network may or may not have been created. + * Level - 3: Disconnect & remove network and try to remove containers. The containers may + * not have been created. Level - 4: Remove containers. Level - 5: Remove db entry. + * @param string $site_name Name of the site to be deleted. + * @param string $site_root Webroot of the site. + */ + protected function delete_site( $level, $site_name, $site_root ) { + + $this->fs = new Filesystem(); + $proxy_type = EE_PROXY_TYPE; + if ( $level >= 3 ) { + if ( EE::docker()::docker_compose_down( $site_root ) ) { + EE::log( "[$site_name] Docker Containers removed." ); + } else { + EE::exec( "docker rm -f $(docker ps -q -f=label=created_by=EasyEngine -f=label=site_name=$site_name)" ); + if ( $level > 3 ) { + EE::warning( 'Error in removing docker containers.' ); + } + } + } + + if ( $this->fs->exists( $site_root ) ) { + try { + $this->fs->remove( $site_root ); + } catch ( Exception $e ) { + EE::debug( $e ); + EE::error( 'Could not remove site root. Please check if you have sufficient rights.' ); + } + EE::log( "[$site_name] site root removed." ); + } + + $config_file_path = EE_CONF_ROOT . '/nginx/conf.d/' . $site_name . '-redirect.conf'; + + if ( $this->fs->exists( $config_file_path ) ) { + try { + $this->fs->remove( $config_file_path ); + } catch ( Exception $e ) { + EE::debug( $e ); + EE::error( 'Could not remove site redirection file. Please check if you have sufficient rights.' ); + } + } + + + if ( $level > 4 ) { + if ( $this->ssl ) { + EE::log( 'Removing ssl certs.' ); + $crt_file = EE_CONF_ROOT . "/nginx/certs/$site_name.crt"; + $key_file = EE_CONF_ROOT . "/nginx/certs/$site_name.key"; + $conf_certs = EE_CONF_ROOT . "/acme-conf/certs/$site_name"; + $conf_var = EE_CONF_ROOT . "/acme-conf/var/$site_name"; + + $cert_files = [$conf_certs, $conf_var, $crt_file, $key_file]; + try { + $this->fs->remove( $cert_files ); + } catch ( Exception $e ) { + EE::warning( $e ); + } + } + + if ( Site::find( $site_name )->delete() ) { + EE::log( 'Removed database entry.' ); + } else { + EE::error( 'Could not remove the database entry' ); + } + } + EE::log( "Site $site_name deleted." ); + } + + /** + * Enables a website. It will start the docker containers of the website if they are stopped. + * + * ## OPTIONS + * + * [] + * : Name of website to be enabled. + * + * [--force] + * : Force execution of site up. + */ + public function up( $args, $assoc_args ) { + + EE\Utils\delem_log( 'site enable start' ); + $force = EE\Utils\get_flag_value( $assoc_args, 'force' ); + $args = EE\SiteUtils\auto_site_name( $args, 'site', __FUNCTION__ ); + $this->populate_site_info( $args ); + $site = Site::find( $this->site['url'] ); + + if ( $site->site_enabled && ! $force ) { + EE::error( sprintf( '%s is already enabled!', $site->site_url ) ); + } + + EE::log( sprintf( 'Enabling site %s.', $site->site_url ) ); + + if ( EE::docker()::docker_compose_up( $this->site['root'] ) ) { + $site->site_enabled = 1; + $site->save(); + EE::success( "Site $site->site_url enabled." ); + } else { + EE::error( sprintf( 'There was error in enabling %s. Please check logs.', $site->site_url ) ); + } + EE\Utils\delem_log( 'site enable end' ); + } + + /** + * Disables a website. It will stop and remove the docker containers of the website if they are running. + * + * ## OPTIONS + * + * [] + * : Name of website to be disabled. + */ + public function down( $args, $assoc_args ) { + + EE\Utils\delem_log( 'site disable start' ); + $args = EE\SiteUtils\auto_site_name( $args, 'site', __FUNCTION__ ); + $this->populate_site_info( $args ); + + $site = Site::find($this->site['url']); + + EE::log( sprintf( 'Disabling site %s.', $site->site_url ) ); + + if ( EE::docker()::docker_compose_down( $this->site['root'] ) ) { + $site->site_enabled = 0; + $site->save(); + + EE::success( sprintf( 'Site %s disabled.', $this->site['url'] ) ); + } else { + EE::error( sprintf( 'There was error in disabling %s. Please check logs.', $this->site['url'] ) ); + } + EE\Utils\delem_log( 'site disable end' ); + } + + /** + * Restarts containers associated with site. + * When no service(--nginx etc.) is specified, all site containers will be restarted. + * + * [] + * : Name of the site. + * + * [--all] + * : Restart all containers of site. + * + * [--nginx] + * : Restart nginx container of site. + */ + public function restart( $args, $assoc_args, $whitelisted_containers = [] ) { + + EE\Utils\delem_log( 'site restart start' ); + $args = EE\SiteUtils\auto_site_name( $args, 'site', __FUNCTION__ ); + $all = EE\Utils\get_flag_value( $assoc_args, 'all' ); + $no_service_specified = count( $assoc_args ) === 0; + + $this->populate_site_info( $args ); + + chdir( $this->site['root'] ); + + if ( $all || $no_service_specified ) { + $containers = $whitelisted_containers; + } else { + $containers = array_keys( $assoc_args ); + } + + foreach ( $containers as $container ) { + EE\Siteutils\run_compose_command( 'restart', $container ); + } + EE\Utils\delem_log( 'site restart stop' ); + } + + /** + * Reload services in containers without restarting container(s) associated with site. + * When no service(--nginx etc.) is specified, all services will be reloaded. + * + * [] + * : Name of the site. + * + * [--all] + * : Reload all services of site(which are supported). + * + * [--nginx] + * : Reload nginx service in container. + * + */ + public function reload( $args, $assoc_args, $whitelisted_containers = [], $reload_commands = [] ) { + + EE\Utils\delem_log( 'site reload start' ); + $args = EE\SiteUtils\auto_site_name( $args, 'site', __FUNCTION__ ); + $all = EE\Utils\get_flag_value( $assoc_args, 'all' ); + if ( !array_key_exists( 'nginx', $reload_commands ) ) { + $reload_commands['nginx'] = 'nginx sh -c \'nginx -t && service openresty reload\''; + } + $no_service_specified = count( $assoc_args ) === 0; + + $this->populate_site_info( $args ); + + chdir( $this->site['root'] ); + + if ( $all || $no_service_specified ) { + $this->reload_services( $whitelisted_containers, $reload_commands ); + } else { + $this->reload_services( array_keys( $assoc_args ), $reload_commands ); + } + EE\Utils\delem_log( 'site reload stop' ); + } + + /** + * Executes reload commands. It needs separate handling as commands to reload each service is different. + * + * @param array $services Services to reload. + * @param array $reload_commands Commands to reload the services. + */ + private function reload_services( $services, $reload_commands ) { + + foreach ( $services as $service ) { + EE\SiteUtils\run_compose_command( 'exec', $reload_commands[$service], 'reload', $service ); + } + } + + /** + * Runs the acme le registration and authorization. + * + * @param string $site_name Name of the site for ssl. + * + * @throws Exception + */ + protected function inherit_certs( $site_name ) { + $parent_site_name = implode( '.', array_slice( explode( '.', $site_name ), 1 ) ); + $parent_site = Site::find( $parent_site_name, [ 'site_ssl', 'site_ssl_wildcard' ] ); + + if ( ! $parent_site ) { + throw new Exception( 'Unable to find existing site: ' . $parent_site_name ); + } + + if ( ! $parent_site->site_ssl ) { + throw new Exception( "Cannot inherit from $parent_site_name as site does not have SSL cert" . var_dump( $parent_site ) ); + } + + if ( ! $parent_site->site_ssl_wildcard ) { + throw new Exception( "Cannot inherit from $parent_site_name as site does not have wildcard SSL cert" ); + } + + // We don't have to do anything now as nginx-proxy handles everything for us. + EE::success( 'Inherited certs from parent' ); + } + + /** + * Runs SSL procedure. + * + * @param string $site_name Name of the site for ssl. + * @param string $site_root Webroot of the site. + * @param string $ssl_type Type of ssl cert to issue. + * @param bool $wildcard SSL with wildcard or not. + * + * @throws \EE\ExitException If --ssl flag has unrecognized value + */ + protected function init_ssl( $site_name, $site_root, $ssl_type, $wildcard = false ) { + EE::debug( 'Starting SSL procedure' ); + if ( 'le' === $ssl_type ) { + EE::debug( 'Initializing LE' ); + $this->init_le( $site_name, $site_root, $wildcard ); + } elseif ( 'inherit' === $ssl_type ) { + if ( $wildcard ) { + EE::error( 'Cannot use --wildcard with --ssl=inherit', false ); + } + EE::debug( 'Inheriting certs' ); + $this->inherit_certs( $site_name ); + } else { + EE::error( "Unrecognized value in --ssl flag: $ssl_type" ); + } + } + + /** + * Runs the acme le registration and authorization. + * + * @param string $site_name Name of the site for ssl. + * @param string $site_root Webroot of the site. + * @param bool $wildcard SSL with wildcard or not. + */ + protected function init_le( $site_name, $site_root, $wildcard = false ) { + EE::debug( "Wildcard in init_le: $wildcard" ); + + $this->site['url'] = $site_name; + $this->site['root'] = $site_root; + $this->wildcard = $wildcard; + $client = new Site_Letsencrypt(); + $this->le_mail = EE::get_runner()->config['le-mail'] ?? EE::input( 'Enter your mail id: ' ); + EE::get_runner()->ensure_present_in_config( 'le-mail', $this->le_mail ); + if ( ! $client->register( $this->le_mail ) ) { + $this->ssl = null; + + return; + } + + $domains = $this->get_cert_domains( $site_name, $wildcard ); + + if ( ! $client->authorize( $domains, $this->site['root'], $wildcard ) ) { + $this->le = false; + + return; + } + if ( $wildcard ) { + echo \cli\Colors::colorize( '%YIMPORTANT:%n Run `ee site le ' . $this->site['url'] . '` once the dns changes have propogated to complete the certification generation and installation.', null ); + } else { + $this->le( [], [] ); + } + } + + /** + * Returns all domains required by cert + * + * @param string $site_name Name of site + * @param $wildcard Wildcard cert required? + * + * @return array + */ + private function get_cert_domains( string $site_name, $wildcard ) : array { + $domains = [ $site_name ]; + $has_www = ( strpos( $site_name, 'www.' ) === 0 ); + + if ( $wildcard ) { + $domains[] = "*.{$site_name}"; + } else { + $domains[] = $this->get_www_domain( $site_name ); + } + return $domains; + } + + /** + * If the domain has www in it, returns a domain without www in it. + * Else returns a domain with www in it. + * + * @param string $site_name Name of site + * + * @return string Domain name with or without www + */ + private function get_www_domain( string $site_name ) : string { + $has_www = ( strpos( $site_name, 'www.' ) === 0 ); + + if ( $has_www ) { + return ltrim( $site_name, 'www.' ); + } else { + return 'www.' . $site_name; + } + } + + + /** + * Runs the acme le. + * + * ## OPTIONS + * + * + * : Name of website. + * + * [--force] + * : Force renewal. + */ + public function le( $args = [], $assoc_args = [] ) { + + if ( !isset( $this->site['url'] ) ) { + $this->populate_site_info( $args ); + } + + if ( !isset( $this->le_mail ) ) { + $this->le_mail = EE::get_config( 'le-mail' ) ?? EE::input( 'Enter your mail id: ' ); + } + + $force = EE\Utils\get_flag_value( $assoc_args, 'force' ); + $domains = $this->get_cert_domains( $this->site['url'], $this->wildcard ); + $client = new Site_Letsencrypt(); + + if ( ! $client->check( $domains, $this->wildcard ) ) { + $this->ssl = null; + return; + } + + $san = array_values( array_diff( $domains, [ $this->site['url'] ] ) ); + $client->request( $this->site['url'], $san, $this->le_mail, $force ); + + if ( ! $this->wildcard ) { + $client->cleanup( $this->site['root'] ); + } + EE::launch( 'docker exec ee-nginx-proxy sh -c "/app/docker-entrypoint.sh /usr/local/bin/docker-gen /app/nginx.tmpl /etc/nginx/conf.d/default.conf; /usr/sbin/nginx -s reload"' ); + } + + /** + * Populate basic site info from db. + */ + private function populate_site_info( $args ) { + + $this->site['url'] = EE\Utils\remove_trailing_slash( $args[0] ); + $site = Site::find( $this->site['url'] ); + if ( $site ) { + + $db_select = $site->site_url; + + $this->site['type'] = $site->site_type; + $this->site['root'] = $site->site_fs_path; + $this->ssl = $site->site_ssl; + $this->wildcard = $site->site_ssl_wildcard; + } else { + EE::error( sprintf( 'Site %s does not exist.', $this->site['url'] ) ); + } + } + + abstract public function create( $args, $assoc_args ); + +} diff --git a/src/site-utils.php b/src/site-utils.php new file mode 100644 index 00000000..0e44cb34 --- /dev/null +++ b/src/site-utils.php @@ -0,0 +1,370 @@ +site_fs_path; + if ( substr( $cwd, 0, strlen( $site_path ) ) === $site_path ) { + return $name; + } + } + } + } + + return false; +} + +/** + * Function to set the site-name in the args when ee is running in a site folder and the site-name has not been passed + * in the args. If the site-name could not be found it will throw an error. + * + * @param array $args The passed arguments. + * @param String $command The command passing the arguments to auto-detect site-name. + * @param String $function The function passing the arguments to auto-detect site-name. + * @param integer $arg_pos Argument position where Site-name will be present. + * + * @return array Arguments with site-name set. + */ +function auto_site_name( $args, $command, $function, $arg_pos = 0 ) { + + if ( isset( $args[ $arg_pos ] ) ) { + $possible_site_name = $args[ $arg_pos ]; + if( substr( $possible_site_name, 0, 4 ) === 'http' ) { + $possible_site_name = str_replace(['https','http'],'',$possible_site_name); + } + $url_path = parse_url(EE\Utils\remove_trailing_slash($possible_site_name), PHP_URL_PATH); + if ( Site::find( $url_path ) ) { + return $args; + } + } + $site_name = get_site_name(); + if ( $site_name ) { + if ( isset( $args[ $arg_pos ] ) ) { + EE::error( $args[ $arg_pos ] . " is not a valid site-name. Did you mean `ee $command $function $site_name`?" ); + } + array_splice( $args, $arg_pos, 0, $site_name ); + } else { + EE::error( "Could not find the site you wish to run $command $function command on.\nEither pass it as an argument: `ee $command $function ` \nor run `ee $command $function` from inside the site folder." ); + } + + return $args; +} + + +/** + * Function to check all the required configurations needed to create the site. + * + * Boots up the container if it is stopped or not running. + */ +function init_checks() { + + $proxy_type = EE_PROXY_TYPE; + if ( 'running' !== EE::docker()::container_status( $proxy_type ) ) { + /** + * Checking ports. + */ + $port_80_status = get_curl_info( 'localhost', 80, true ); + $port_443_status = get_curl_info( 'localhost', 443, true ); + + // if any/both the port/s is/are occupied. + if ( ! ( $port_80_status && $port_443_status ) ) { + EE::error( 'Cannot create/start proxy container. Please make sure port 80 and 443 are free.' ); + } else { + + $fs = new Filesystem(); + + if ( ! $fs->exists( EE_CONF_ROOT . '/docker-compose.yml' ) ) { + generate_global_docker_compose_yml( $fs ); + } + + $EE_CONF_ROOT = EE_CONF_ROOT; + if ( ! EE::docker()::docker_network_exists( 'ee-global-network' ) ) { + if ( ! EE::docker()::create_network( 'ee-global-network' ) ) { + EE::error( 'Unable to create network ee-global-network' ); + } + } + if ( EE::docker()::docker_compose_up( EE_CONF_ROOT, [ 'nginx-proxy' ] ) ) { + $fs->dumpFile( "$EE_CONF_ROOT/nginx/conf.d/custom.conf", file_get_contents( EE_ROOT . '/templates/custom.conf.mustache' ) ); + EE::success( "$proxy_type container is up." ); + } else { + EE::error( "There was some error in starting $proxy_type container. Please check logs." ); + } + } + } +} + +/** + * Generates global docker-compose.yml at EE_CONF_ROOT + * + * @param Filesystem $fs Filesystem object to write file + */ +function generate_global_docker_compose_yml( Filesystem $fs ) { + $img_versions = EE\Utils\get_image_versions(); + + $data = [ + 'services' => [ + 'name' => 'nginx-proxy', + 'container_name' => 'ee-nginx-proxy', + 'image' => 'easyengine/nginx-proxy:' . $img_versions['easyengine/nginx-proxy'], + 'restart' => 'always', + 'ports' => [ + '80:80', + '443:443', + ], + 'environment' => [ + 'LOCAL_USER_ID=' . posix_geteuid(), + 'LOCAL_GROUP_ID=' . posix_getegid(), + ], + 'volumes' => [ + EE_CONF_ROOT . '/nginx/certs:/etc/nginx/certs', + EE_CONF_ROOT . '/nginx/dhparam:/etc/nginx/dhparam', + EE_CONF_ROOT . '/nginx/conf.d:/etc/nginx/conf.d', + EE_CONF_ROOT . '/nginx/htpasswd:/etc/nginx/htpasswd', + EE_CONF_ROOT . '/nginx/vhost.d:/etc/nginx/vhost.d', + '/usr/share/nginx/html', + '/var/run/docker.sock:/tmp/docker.sock:ro', + ], + 'networks' => [ + 'global-network', + ], + ], + ]; + + $contents = EE\Utils\mustache_render( EE_ROOT . '/templates/global_docker_compose.yml.mustache', $data ); + $fs->dumpFile( EE_CONF_ROOT . '/docker-compose.yml', $contents ); +} + +/** + * Creates site root directory if does not exist. + * Throws error if it does exist. + * + * @param string $site_root Root directory of the site. + * @param string $site_name Name of the site. + */ +function create_site_root( $site_root, $site_name ) { + + $fs = new Filesystem(); + if ( $fs->exists( $site_root ) ) { + EE::error( "Webroot directory for site $site_name already exists." ); + } + + $whoami = EE::launch( 'whoami', false, true ); + $terminal_username = rtrim( $whoami->stdout ); + + $fs->mkdir( $site_root ); + $fs->chown( $site_root, $terminal_username ); +} + +/** + * Reloads configuration of ee-nginx-proxy container + * + * @return bool + */ +function reload_proxy_configuration() { + return EE::exec( 'docker exec ee-nginx-proxy sh -c "/app/docker-entrypoint.sh /usr/local/bin/docker-gen /app/nginx.tmpl /etc/nginx/conf.d/default.conf; /usr/sbin/nginx -s reload"' ); +} + +/** + * Adds www to non-www redirection to site + * + * @param string $site_name name of the site. + * @param bool $ssl enable ssl or not. + * @param bool $inherit inherit cert or not. + */ +function add_site_redirects( string $site_name, bool $ssl, bool $inherit ) { + + $fs = new Filesystem(); + $confd_path = EE_CONF_ROOT . '/nginx/conf.d/'; + $config_file_path = $confd_path . $site_name . '-redirect.conf'; + $has_www = strpos( $site_name, 'www.' ) === 0; + $cert_site_name = $site_name; + + if ( $inherit ) { + $cert_site_name = implode( '.', array_slice( explode( '.', $site_name ), 1 ) ); + } + + if ( $has_www ) { + $server_name = ltrim( $site_name, '.www' ); + } else { + $server_name = 'www.' . $site_name; + } + + $conf_data = [ + 'site_name' => $site_name, + 'cert_site_name' => $cert_site_name, + 'server_name' => $server_name, + 'ssl' => $ssl, + ]; + + $content = EE\Utils\mustache_render( EE_ROOT . '/templates/redirect.conf.mustache', $conf_data ); + $fs->dumpFile( $config_file_path, ltrim( $content, PHP_EOL ) ); +} + +/** + * Function to create entry in /etc/hosts. + * + * @param string $site_name Name of the site. + */ +function create_etc_hosts_entry( $site_name ) { + + $host_line = LOCALHOST_IP . "\t$site_name"; + $etc_hosts = file_get_contents( '/etc/hosts' ); + if ( ! preg_match( "/\s+$site_name\$/m", $etc_hosts ) ) { + if ( EE::exec( "/bin/bash -c 'echo \"$host_line\" >> /etc/hosts'" ) ) { + EE::success( 'Host entry successfully added.' ); + } else { + EE::warning( "Failed to add $site_name in host entry, Please do it manually!" ); + } + } else { + EE::log( 'Host entry already exists.' ); + } +} + + +/** + * Checking site is running or not. + * + * @param string $site_name Name of the site. + * + * @throws \Exception when fails to connect to site. + */ +function site_status_check( $site_name ) { + + EE::log( 'Checking and verifying site-up status. This may take some time.' ); + $httpcode = get_curl_info( $site_name ); + $i = 0; + while ( 200 !== $httpcode && 302 !== $httpcode && 301 !== $httpcode ) { + EE::debug( "$site_name status httpcode: $httpcode" ); + $httpcode = get_curl_info( $site_name ); + echo '.'; + sleep( 2 ); + if ( $i ++ > 60 ) { + break; + } + } + if ( 200 !== $httpcode && 302 !== $httpcode && 301 !== $httpcode ) { + throw new \Exception( 'Problem connecting to site!' ); + } + +} + +/** + * Function to get httpcode or port occupancy info. + * + * @param string $url url to get info about. + * @param int $port The port to check. + * @param bool $port_info Return port info or httpcode. + * + * @return bool|int port occupied or httpcode. + */ +function get_curl_info( $url, $port = 80, $port_info = false ) { + + $ch = curl_init( $url ); + curl_setopt( $ch, CURLOPT_HEADER, true ); + curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 ); + curl_setopt( $ch, CURLOPT_NOBODY, true ); + curl_setopt( $ch, CURLOPT_TIMEOUT, 10 ); + curl_setopt( $ch, CURLOPT_PORT, $port ); + curl_exec( $ch ); + if ( $port_info ) { + return empty( curl_getinfo( $ch, CURLINFO_PRIMARY_IP ) ); + } + + return curl_getinfo( $ch, CURLINFO_HTTP_CODE ); +} + +/** + * Function to pull the latest images and bring up the site containers. + * + * @param string $site_root Root directory of the site. + * @param array $containers The minimum required conatainers to start the site. Default null, leads to starting of all containers. + * + * @throws \Exception when docker-compose up fails. + */ +function start_site_containers( $site_root, $containers = [] ) { + + EE::log( 'Pulling latest images. This may take some time.' ); + chdir( $site_root ); + EE::exec( 'docker-compose pull' ); + EE::log( 'Starting site\'s services.' ); + if ( ! EE::docker()::docker_compose_up( $site_root, $containers ) ) { + throw new \Exception( 'There was some error in docker-compose up.' ); + } +} + + +/** + * Generic function to run a docker compose command. Must be ran inside correct directory. + * + * @param string $action docker-compose action to run. + * @param string $container The container on which action has to be run. + * @param string $action_to_display The action message to be displayed. + * @param string $service_to_display The service message to be displayed. + */ +function run_compose_command( $action, $container, $action_to_display = null, $service_to_display = null ) { + + $display_action = $action_to_display ? $action_to_display : $action; + $display_service = $service_to_display ? $service_to_display : $container; + + EE::log( ucfirst( $display_action ) . 'ing ' . $display_service ); + EE::exec( "docker-compose $action $container", true, true ); +} + +/** + * Function to copy and configure files needed for postfix. + * + * @param string $site_name Name of the site to configure postfix files for. + * @param string $site_conf_dir Configuration directory of the site `site_root/config`. + */ +function set_postfix_files( $site_name, $site_conf_dir ) { + + $fs = new Filesystem(); + $fs->mkdir( $site_conf_dir . '/postfix' ); + $fs->mkdir( $site_conf_dir . '/postfix/ssl' ); + $ssl_dir = $site_conf_dir . '/postfix/ssl'; + + if ( ! EE::exec( sprintf( "openssl req -new -x509 -nodes -days 365 -subj \"/CN=smtp.%s\" -out $ssl_dir/server.crt -keyout $ssl_dir/server.key", $site_name ) ) + && EE::exec( "chmod 0600 $ssl_dir/server.key" ) ) { + throw new Exception( 'Unable to generate ssl key for postfix' ); + } +} + +/** + * Function to execute docker-compose exec calls to postfix to get it configured and running for the site. + * + * @param string $site_name Name of the for which postfix has to be configured. + * @param strin $site_root Site root. + */ +function configure_postfix( $site_name, $site_root ) { + + chdir( $site_root ); + EE::exec( 'docker-compose exec postfix postconf -e \'relayhost =\'' ); + EE::exec( 'docker-compose exec postfix postconf -e \'smtpd_recipient_restrictions = permit_mynetworks\'' ); + $launch = EE::launch( sprintf( 'docker inspect -f \'{{ with (index .IPAM.Config 0) }}{{ .Subnet }}{{ end }}\' %s', $site_name ) ); + $subnet_cidr = trim( $launch->stdout ); + EE::exec( sprintf( 'docker-compose exec postfix postconf -e \'mynetworks = %s 127.0.0.0/8\'', $subnet_cidr ) ); + EE::exec( sprintf( 'docker-compose exec postfix postconf -e \'myhostname = %s\'', $site_name ) ); + EE::exec( 'docker-compose exec postfix postconf -e \'syslog_name = $myhostname\'' ); + EE::exec( 'docker-compose restart postfix' ); +} From ab8c4d0e2825a9bb218e9cce7f22c56fb6f02b52 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Tue, 28 Aug 2018 15:38:13 +0530 Subject: [PATCH 28/81] Update composer dependencies Signed-off-by: Riddhesh Sanghvi --- composer.json | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index 8faa7653..2303c5bc 100644 --- a/composer.json +++ b/composer.json @@ -18,12 +18,14 @@ "branch-alias": { "dev-master": "1.x-dev" }, - "bundled": true, - "commands": [ - "site", - "site create", - "site list", - "site delete" - ] + "bundled": true + }, + "require": { + "acmephp/core": "dev-master", + "ext-openssl": "*", + "guzzlehttp/guzzle": "^6.0", + "league/flysystem": "^1.0.19", + "symfony/serializer": "^3.0", + "webmozart/assert": "^1.0" } } From 74dbc3a5baf482b1d9917d88a7a4d36c45f7c1f3 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Tue, 28 Aug 2018 16:45:03 +0530 Subject: [PATCH 29/81] Update namespaces and change Site_Command to HTML site-type Signed-off-by: Riddhesh Sanghvi --- src/HTML.php | 355 +++++++++++++++++++++++++++++++++++++++++++++ src/site-utils.php | 2 +- 2 files changed, 356 insertions(+), 1 deletion(-) create mode 100644 src/HTML.php diff --git a/src/HTML.php b/src/HTML.php new file mode 100644 index 00000000..6f5b5eb8 --- /dev/null +++ b/src/HTML.php @@ -0,0 +1,355 @@ +level = 0; + pcntl_signal( SIGTERM, [ $this, "rollback" ] ); + pcntl_signal( SIGHUP, [ $this, "rollback" ] ); + pcntl_signal( SIGUSR1, [ $this, "rollback" ] ); + pcntl_signal( SIGINT, [ $this, "rollback" ] ); + $shutdown_handler = new Shutdown_Handler(); + register_shutdown_function( [ $shutdown_handler, "cleanup" ], [ &$this ] ); + $this->docker = EE::docker(); + $this->logger = EE::get_file_logger()->withName( 'site_command' ); + $this->fs = new Filesystem(); + } + + /** + * Runs the standard WordPress site installation. + * + * ## OPTIONS + * + * + * : Name of website. + * + * [--ssl=] + * : Enables ssl via letsencrypt certificate. + * + * [--wildcard] + * : Gets wildcard SSL . + * [--type=] + * : Type of the site to be created. Values: html,php,wp. + * + * [--skip-status-check] + * : Skips site status check. + */ + public function create( $args, $assoc_args ) { + + EE\Utils\delem_log( 'site create start' ); + EE::warning( 'This is a beta version. Please don\'t use it in production.' ); + $this->logger->debug( 'args:', $args ); + $this->logger->debug( 'assoc_args:', empty( $assoc_args ) ? [ 'NULL' ] : $assoc_args ); + $this->site['url'] = strtolower( EE\Utils\remove_trailing_slash( $args[0] ) ); + $this->site['type'] = EE\Utils\get_flag_value( $assoc_args, 'type', 'html' ); + if ( 'html' !== $this->site['type'] ) { + EE::error( sprintf( 'Invalid site-type: %s', $this->site['type'] ) ); + } + + if ( Site::find( $this->site['url'] ) ) { + EE::error( sprintf( "Site %1\$s already exists. If you want to re-create it please delete the older one using:\n`ee site delete %1\$s`", $this->site['url'] ) ); + } + + $this->ssl = EE\Utils\get_flag_value( $assoc_args, 'ssl' ); + $this->ssl_wildcard = EE\Utils\get_flag_value( $assoc_args, 'wildcard' ); + $this->skip_chk = EE\Utils\get_flag_value( $assoc_args, 'skip-status-check' ); + + EE\Site\Utils\init_checks(); + + EE::log( 'Configuring project.' ); + + $this->create_site(); + EE\Utils\delem_log( 'site create end' ); + } + + /** + * Display all the relevant site information, credentials and useful links. + * + * [] + * : Name of the website whose info is required. + */ + public function info( $args, $assoc_args ) { + + EE\Utils\delem_log( 'site info start' ); + if ( ! isset( $this->site['url'] ) ) { + $args = EE\Site\Utils\auto_site_name( $args, 'site', __FUNCTION__ ); + $this->populate_site_info( $args ); + } + $ssl = $this->ssl ? 'Enabled' : 'Not Enabled'; + $prefix = ( $this->ssl ) ? 'https://' : 'http://'; + $info = [ + [ 'Site', $prefix . $this->site['url'] ], + [ 'Site Root', $this->site['root'] ], + [ 'SSL', $ssl ], + ]; + + if ( $this->ssl ) { + $info[] = [ 'SSL Wildcard', $this->ssl_wildcard ? 'Yes': 'No' ]; + } + + EE\Utils\format_table( $info ); + + EE\Utils\delem_log( 'site info end' ); + } + + + /** + * Function to configure site and copy all the required files. + */ + private function configure_site_files() { + + $site_conf_dir = $this->site['root'] . '/config'; + $site_docker_yml = $this->site['root'] . '/docker-compose.yml'; + $site_conf_env = $this->site['root'] . '/.env'; + $site_nginx_default_conf = $site_conf_dir . '/nginx/default.conf'; + $site_src_dir = $this->site['root'] . '/app/src'; + $process_user = posix_getpwuid( posix_geteuid() ); + + EE::log( sprintf( 'Creating site %s.', $this->site['url'] ) ); + EE::log( 'Copying configuration files.' ); + + $filter = []; + $filter[] = $this->site['type']; + $site_docker = new Site_Docker(); + $docker_compose_content = $site_docker->generate_docker_compose_yml( $filter ); + $default_conf_content = $default_conf_content = EE\Utils\mustache_render( SITE_TEMPLATE_ROOT . '/config/nginx/default.conf.mustache', [ 'server_name' => $this->site['url'] ] ); + + $env_data = [ + 'virtual_host' => $this->site['url'], + 'user_id' => $process_user['uid'], + 'group_id' => $process_user['gid'], + ]; + $env_content = EE\Utils\mustache_render( SITE_TEMPLATE_ROOT . '/config/.env.mustache', $env_data ); + + try { + $this->fs->dumpFile( $site_docker_yml, $docker_compose_content ); + $this->fs->dumpFile( $site_conf_env, $env_content ); + $this->fs->mkdir( $site_conf_dir ); + $this->fs->mkdir( $site_conf_dir . '/nginx' ); + $this->fs->dumpFile( $site_nginx_default_conf, $default_conf_content ); + + $index_data = [ + 'version' => 'v' . EE_VERSION, + 'site_src_root' => $this->site['root'] . '/app/src', + ]; + $index_html = EE\Utils\mustache_render( SITE_TEMPLATE_ROOT . '/index.html.mustache', $index_data ); + $this->fs->mkdir( $site_src_dir ); + $this->fs->dumpFile( $site_src_dir . '/index.html', $index_html ); + + EE::success( 'Configuration files copied.' ); + } catch ( Exception $e ) { + $this->catch_clean( $e ); + } + } + + /** + * Function to create the site. + */ + private function create_site() { + + $this->site['root'] = WEBROOT . $this->site['url']; + $this->level = 1; + try { + EE\Site\Utils\create_site_root( $this->site['root'], $this->site['url'] ); + $this->level = 3; + $this->configure_site_files(); + + EE\Site\Utils\start_site_containers( $this->site['root'] ); + + EE\Site\Utils\create_etc_hosts_entry( $this->site['url'] ); + if ( ! $this->skip_chk ) { + $this->level = 4; + EE\Site\Utils\site_status_check( $this->site['url'] ); + } + + /* + * This adds http www redirection which is needed for issuing cert for a site. + * i.e. when you create example.com site, certs are issued for example.com and www.example.com + * + * We're issuing certs for both domains as it is needed in order to perform redirection of + * https://www.example.com -> https://example.com + * + * We add redirection config two times in case of ssl as we need http redirection + * when certs are being requested and http+https redirection after we have certs. + */ + EE\Site\Utils\add_site_redirects( $this->site['url'], false, 'inherit' === $this->ssl ); + EE\Site\Utils\reload_proxy_configuration(); + + if ( $this->ssl ) { + $this->init_ssl( $this->site['url'], $this->site['root'], $this->ssl, $this->ssl_wildcard ); + EE\Site\Utils\add_site_redirects( $this->site['url'], true, 'inherit' === $this->ssl ); + EE\Site\Utils\reload_proxy_configuration(); + } + } catch ( Exception $e ) { + $this->catch_clean( $e ); + } + + $this->info( [ $this->site['url'] ], [] ); + $this->create_site_db_entry(); + } + + /** + * Function to save the site configuration entry into database. + */ + private function create_site_db_entry() { + + $ssl = $this->ssl ? 1 : 0; + $ssl_wildcard = $this->ssl_wildcard ? 1 : 0; + + $site = Site::create([ + 'site_url' => $this->site['url'], + 'site_type' => $this->site['type'], + 'site_fs_path' => $this->site['root'], + 'site_ssl' => $ssl, + 'site_ssl_wildcard' => $ssl_wildcard, + 'created_on' => date( 'Y-m-d H:i:s', time() ), + ]); + + try { + if ( $site ) { + EE::log( 'Site entry created.' ); + } else { + throw new Exception( 'Error creating site entry in database.' ); + } + } catch ( Exception $e ) { + $this->catch_clean( $e ); + } + } + + /** + * Populate basic site info from db. + */ + private function populate_site_info( $args ) { + + $this->site['url'] = EE\Utils\remove_trailing_slash( $args[0] ); + + $site = Site::find( $this->site['url'] ); + + if ( $site ) { + $this->site['type'] = $site->site_type; + $this->site['root'] = $site->site_fs_path; + $this->ssl = $site->site_ssl; + $this->ssl_wildcard = $site->site_ssl_wildcard; + } else { + EE::error( sprintf( 'Site %s does not exist.', $this->site['url'] ) ); + } + } + + /** + * @inheritdoc + */ + public function restart( $args, $assoc_args, $whitelisted_containers = [] ) { + $whitelisted_containers = [ 'nginx' ]; + parent::restart( $args, $assoc_args, $whitelisted_containers ); + } + + /** + * @inheritdoc + */ + public function reload( $args, $assoc_args, $whitelisted_containers = [], $reload_commands = [] ) { + $whitelisted_containers = [ 'nginx' ]; + parent::reload( $args, $assoc_args, $whitelisted_containers, $reload_commands = [] ); + } + + /** + * Catch and clean exceptions. + * + * @param Exception $e + */ + private function catch_clean( $e ) { + + EE\Utils\delem_log( 'site cleanup start' ); + EE::warning( $e->getMessage() ); + EE::warning( 'Initiating clean-up.' ); + $this->delete_site( $this->level, $this->site['url'], $this->site['root'] ); + EE\Utils\delem_log( 'site cleanup end' ); + exit; + } + + /** + * Roll back on interrupt. + */ + private function rollback() { + + EE::warning( 'Exiting gracefully after rolling back. This may take some time.' ); + if ( $this->level > 0 ) { + $this->delete_site( $this->level, $this->site['url'], $this->site['root'] ); + } + EE::success( 'Rollback complete. Exiting now.' ); + exit; + } + + /** + * Shutdown function to catch and rollback from fatal errors. + */ + private function shutDownFunction() { + + $error = error_get_last(); + if ( isset( $error ) && $error['type'] === E_ERROR ) { + EE::warning( 'An Error occurred. Initiating clean-up.' ); + $this->logger->error( 'Type: ' . $error['type'] ); + $this->logger->error( 'Message: ' . $error['message'] ); + $this->logger->error( 'File: ' . $error['file'] ); + $this->logger->error( 'Line: ' . $error['line'] ); + $this->rollback(); + } + } +} diff --git a/src/site-utils.php b/src/site-utils.php index 0e44cb34..0783dbc9 100644 --- a/src/site-utils.php +++ b/src/site-utils.php @@ -1,6 +1,6 @@ Date: Tue, 28 Aug 2018 16:46:39 +0530 Subject: [PATCH 30/81] Use constants where applicable Signed-off-by: Riddhesh Sanghvi --- src/site-utils.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/site-utils.php b/src/site-utils.php index 0783dbc9..df9825f5 100644 --- a/src/site-utils.php +++ b/src/site-utils.php @@ -125,7 +125,7 @@ function generate_global_docker_compose_yml( Filesystem $fs ) { $data = [ 'services' => [ 'name' => 'nginx-proxy', - 'container_name' => 'ee-nginx-proxy', + 'container_name' => EE_PROXY_TYPE, 'image' => 'easyengine/nginx-proxy:' . $img_versions['easyengine/nginx-proxy'], 'restart' => 'always', 'ports' => [ @@ -177,12 +177,12 @@ function create_site_root( $site_root, $site_name ) { } /** - * Reloads configuration of ee-nginx-proxy container + * Reloads configuration of global-proxy container * * @return bool */ function reload_proxy_configuration() { - return EE::exec( 'docker exec ee-nginx-proxy sh -c "/app/docker-entrypoint.sh /usr/local/bin/docker-gen /app/nginx.tmpl /etc/nginx/conf.d/default.conf; /usr/sbin/nginx -s reload"' ); + return EE::exec( sprintf( 'docker exec %s sh -c "/app/docker-entrypoint.sh /usr/local/bin/docker-gen /app/nginx.tmpl /etc/nginx/conf.d/default.conf; /usr/sbin/nginx -s reload"', EE_PROXY_TYPE ) ); } /** From 7dbb02fe9e9bf3f9e382be01edcb9d4f7e2e6012 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Tue, 28 Aug 2018 17:44:05 +0530 Subject: [PATCH 31/81] Add site-type routing in site-command Signed-off-by: Riddhesh Sanghvi --- src/Site_Command.php | 389 ++++++++++--------------------------------- 1 file changed, 89 insertions(+), 300 deletions(-) diff --git a/src/Site_Command.php b/src/Site_Command.php index e5b8c355..07a600e5 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -1,354 +1,143 @@ level = 0; - pcntl_signal( SIGTERM, [ $this, "rollback" ] ); - pcntl_signal( SIGHUP, [ $this, "rollback" ] ); - pcntl_signal( SIGUSR1, [ $this, "rollback" ] ); - pcntl_signal( SIGINT, [ $this, "rollback" ] ); - $shutdown_handler = new Shutdown_Handler(); - register_shutdown_function( [ $shutdown_handler, "cleanup" ], [ &$this ] ); - $this->docker = EE::docker(); - $this->logger = EE::get_file_logger()->withName( 'site_command' ); - $this->fs = new Filesystem(); - } + private static $instance; /** - * Runs the standard WordPress site installation. + * The singleton method to hold the instance of site-command. * - * ## OPTIONS - * - * - * : Name of website. - * - * [--ssl=] - * : Enables ssl via letsencrypt certificate. - * - * [--wildcard] - * : Gets wildcard SSL . - * [--type=] - * : Type of the site to be created. Values: html,php,wp. - * - * [--skip-status-check] - * : Skips site status check. + * @return Object|Site_Command */ - public function create( $args, $assoc_args ) { - - EE\Utils\delem_log( 'site create start' ); - EE::warning( 'This is a beta version. Please don\'t use it in production.' ); - $this->logger->debug( 'args:', $args ); - $this->logger->debug( 'assoc_args:', empty( $assoc_args ) ? [ 'NULL' ] : $assoc_args ); - $this->site['url'] = strtolower( EE\Utils\remove_trailing_slash( $args[0] ) ); - $this->site['type'] = EE\Utils\get_flag_value( $assoc_args, 'type', 'html' ); - if ( 'html' !== $this->site['type'] ) { - EE::error( sprintf( 'Invalid site-type: %s', $this->site['type'] ) ); - } + public static function instance() { - if ( Site::find( $this->site['url'] ) ) { - EE::error( sprintf( "Site %1\$s already exists. If you want to re-create it please delete the older one using:\n`ee site delete %1\$s`", $this->site['url'] ) ); + if ( ! isset( self::$instance ) ) { + self::$instance = new Site_Command(); } - $this->ssl = EE\Utils\get_flag_value( $assoc_args, 'ssl' ); - $this->ssl_wildcard = EE\Utils\get_flag_value( $assoc_args, 'wildcard' ); - $this->skip_chk = EE\Utils\get_flag_value( $assoc_args, 'skip-status-check' ); - - EE\SiteUtils\init_checks(); - - EE::log( 'Configuring project.' ); - - $this->create_site(); - EE\Utils\delem_log( 'site create end' ); + return self::$instance; } /** - * Display all the relevant site information, credentials and useful links. + * Function to register different site-types. * - * [] - * : Name of the website whose info is required. + * @param string $name Name of the site-type. + * @param string $callback The callback function/class for that type. */ - public function info( $args, $assoc_args ) { - - EE\Utils\delem_log( 'site info start' ); - if ( ! isset( $this->site['url'] ) ) { - $args = EE\SiteUtils\auto_site_name( $args, 'site', __FUNCTION__ ); - $this->populate_site_info( $args ); - } - $ssl = $this->ssl ? 'Enabled' : 'Not Enabled'; - $prefix = ( $this->ssl ) ? 'https://' : 'http://'; - $info = [ - [ 'Site', $prefix . $this->site['url'] ], - [ 'Site Root', $this->site['root'] ], - [ 'SSL', $ssl ], - ]; + public static function add_site_type( $name, $callback ) { - if ( $this->ssl ) { - $info[] = [ 'SSL Wildcard', $this->ssl_wildcard ? 'Yes': 'No' ]; + if ( isset( self::$instance->site_types[ $name ] ) ) { + EE::warning( sprintf( '%s site-type has already been previously registered by %s. It will be over-written by the new package class %s. Please update your packages to resolve this.', $name, self::$instance->site_types[ $name ], $callback ) ); } - - EE\Utils\format_table( $info ); - - EE\Utils\delem_log( 'site info end' ); + self::$instance->site_types[ $name ] = $callback; } - /** - * Function to configure site and copy all the required files. + * Method to get the list of registered site-types. + * + * @return array associative array of site-types and their callbacks. */ - private function configure_site_files() { - - $site_conf_dir = $this->site['root'] . '/config'; - $site_docker_yml = $this->site['root'] . '/docker-compose.yml'; - $site_conf_env = $this->site['root'] . '/.env'; - $site_nginx_default_conf = $site_conf_dir . '/nginx/default.conf'; - $site_src_dir = $this->site['root'] . '/app/src'; - $process_user = posix_getpwuid( posix_geteuid() ); - - EE::log( sprintf( 'Creating site %s.', $this->site['url'] ) ); - EE::log( 'Copying configuration files.' ); - - $filter = []; - $filter[] = $this->site['type']; - $site_docker = new Site_Docker(); - $docker_compose_content = $site_docker->generate_docker_compose_yml( $filter ); - $default_conf_content = $default_conf_content = EE\Utils\mustache_render( SITE_TEMPLATE_ROOT . '/config/nginx/default.conf.mustache', [ 'server_name' => $this->site['url'] ] ); - - $env_data = [ - 'virtual_host' => $this->site['url'], - 'user_id' => $process_user['uid'], - 'group_id' => $process_user['gid'], - ]; - $env_content = EE\Utils\mustache_render( SITE_TEMPLATE_ROOT . '/config/.env.mustache', $env_data ); - - try { - $this->fs->dumpFile( $site_docker_yml, $docker_compose_content ); - $this->fs->dumpFile( $site_conf_env, $env_content ); - $this->fs->mkdir( $site_conf_dir ); - $this->fs->mkdir( $site_conf_dir . '/nginx' ); - $this->fs->dumpFile( $site_nginx_default_conf, $default_conf_content ); - - $index_data = [ - 'version' => 'v' . EE_VERSION, - 'site_src_root' => $this->site['root'] . '/app/src', - ]; - $index_html = EE\Utils\mustache_render( SITE_TEMPLATE_ROOT . '/index.html.mustache', $index_data ); - $this->fs->mkdir( $site_src_dir ); - $this->fs->dumpFile( $site_src_dir . '/index.html', $index_html ); - - EE::success( 'Configuration files copied.' ); - } catch ( Exception $e ) { - $this->catch_clean( $e ); - } + public static function get_site_types() { + return self::$instance->site_types; } /** - * Function to create the site. + * Invoked function of site-type routing. Called when `ee site` is invoked. + * Performs the routing to respective site-type passed using either `--type=`, + * Or discovers the type from the site-name and fetches the type from it, + * Or falls down to the default site-type defined by the user, + * Or finally the most basic site-type and the default included in this package, type=html. */ - private function create_site() { - - $this->site['root'] = WEBROOT . $this->site['url']; - $this->level = 1; - try { - EE\SiteUtils\create_site_root( $this->site['root'], $this->site['url'] ); - $this->level = 3; - $this->configure_site_files(); - - EE\SiteUtils\start_site_containers( $this->site['root'] ); - - EE\SiteUtils\create_etc_hosts_entry( $this->site['url'] ); - if ( ! $this->skip_chk ) { - $this->level = 4; - EE\SiteUtils\site_status_check( $this->site['url'] ); - } + public function __invoke( $args, $assoc_args ) { - /* - * This adds http www redirection which is needed for issuing cert for a site. - * i.e. when you create example.com site, certs are issued for example.com and www.example.com - * - * We're issuing certs for both domains as it is needed in order to perform redirection of - * https://www.example.com -> https://example.com - * - * We add redirection config two times in case of ssl as we need http redirection - * when certs are being requested and http+https redirection after we have certs. - */ - EE\SiteUtils\add_site_redirects( $this->site['url'], false, 'inherit' === $this->ssl ); - EE\SiteUtils\reload_proxy_configuration(); + $site_types = self::get_site_types(); - if ( $this->ssl ) { - $this->init_ssl( $this->site['url'], $this->site['root'], $this->ssl, $this->ssl_wildcard ); - EE\SiteUtils\add_site_redirects( $this->site['url'], true, 'inherit' === $this->ssl ); - EE\SiteUtils\reload_proxy_configuration(); - } - } catch ( Exception $e ) { - $this->catch_clean( $e ); + if ( isset( $assoc_args['type'] ) ) { + $type = $assoc_args['type']; + unset( $assoc_args['type'] ); + } else { + $type = $this->determine_type( $args ); } - - $this->info( [ $this->site['url'] ], [] ); - $this->create_site_db_entry(); - } - - /** - * Function to save the site configuration entry into database. - */ - private function create_site_db_entry() { - - $ssl = $this->ssl ? 1 : 0; - $ssl_wildcard = $this->ssl_wildcard ? 1 : 0; - - $site = Site::create([ - 'site_url' => $this->site['url'], - 'site_type' => $this->site['type'], - 'site_fs_path' => $this->site['root'], - 'site_ssl' => $ssl, - 'site_ssl_wildcard' => $ssl_wildcard, - 'created_on' => date( 'Y-m-d H:i:s', time() ), - ]); - - try { - if ( $site ) { - EE::log( 'Site entry created.' ); - } else { - throw new Exception( 'Error creating site entry in database.' ); - } - } catch ( Exception $e ) { - $this->catch_clean( $e ); + array_unshift( $args, 'site' ); + + if ( ! isset( $site_types[ $type ] ) ) { + $error = sprintf( + "'%s' is not a registered site type of 'ee site --type=%s'. See 'ee help site --type=%s' for available subcommands.", + $type, + $type, + $type + ); + EE::error( $error ); } - } - /** - * Populate basic site info from db. - */ - private function populate_site_info( $args ) { + $callback = $site_types[ $type ]; - $this->site['url'] = EE\Utils\remove_trailing_slash( $args[0] ); + $command = EE::get_root_command(); + $leaf_command = CommandFactory::create( 'site', $callback, $command ); + $command->add_subcommand( 'site', $leaf_command ); - $site = Site::find( $this->site['url'] ); - - if ( $site ) { - $this->site['type'] = $site->site_type; - $this->site['root'] = $site->site_fs_path; - $this->ssl = $site->site_ssl; - $this->ssl_wildcard = $site->site_ssl_wildcard; - } else { - EE::error( sprintf( 'Site %s does not exist.', $this->site['url'] ) ); - } - } - - /** - * @inheritdoc - */ - public function restart( $args, $assoc_args, $whitelisted_containers = [] ) { - $whitelisted_containers = [ 'nginx' ]; - parent::restart( $args, $assoc_args, $whitelisted_containers ); + EE::run_command( $args, $assoc_args ); } /** - * @inheritdoc - */ - public function reload( $args, $assoc_args, $whitelisted_containers = [], $reload_commands = [] ) { - $whitelisted_containers = [ 'nginx' ]; - parent::reload( $args, $assoc_args, $whitelisted_containers, $reload_commands = [] ); - } - - /** - * Catch and clean exceptions. + * Function to determine type. + * + * Discovers the type from the site-name and fetches the type from it, + * Or falls down to the default site-type defined by the user, + * Or finally the most basic site-type and the default included in this package, type=html. + * + * @param array $args Command line arguments passed to site-command. * - * @param Exception $e + * @return string site-type. */ - private function catch_clean( $e ) { + private function determine_type( $args ) { - EE\Utils\delem_log( 'site cleanup start' ); - EE::warning( $e->getMessage() ); - EE::warning( 'Initiating clean-up.' ); - $this->delete_site( $this->level, $this->site['url'], $this->site['root'] ); - EE\Utils\delem_log( 'site cleanup end' ); - exit; - } + // default site-type + $type = 'html'; - /** - * Roll back on interrupt. - */ - private function rollback() { + // TODO: get type from config file as below + // $config_type = EE::get_config('type'); + // $type = empty( $config_type ) ? 'html' : $config_type; - EE::warning( 'Exiting gracefully after rolling back. This may take some time.' ); - if ( $this->level > 0 ) { - $this->delete_site( $this->level, $this->site['url'], $this->site['root'] ); + $last_arg = array_pop( $args ); + if ( substr( $last_arg, 0, 4 ) === 'http' ) { + $last_arg = str_replace( [ 'https://', 'http://' ], '', $last_arg ); } - EE::success( 'Rollback complete. Exiting now.' ); - exit; - } + $url_path = EE\Utils\remove_trailing_slash( $last_arg ); - /** - * Shutdown function to catch and rollback from fatal errors. - */ - private function shutDownFunction() { + $arg_search = Site::find( $url_path, [ 'site_type' ] ); - $error = error_get_last(); - if ( isset( $error ) && $error['type'] === E_ERROR ) { - EE::warning( 'An Error occurred. Initiating clean-up.' ); - $this->logger->error( 'Type: ' . $error['type'] ); - $this->logger->error( 'Message: ' . $error['message'] ); - $this->logger->error( 'File: ' . $error['file'] ); - $this->logger->error( 'Line: ' . $error['line'] ); - $this->rollback(); + if ( $arg_search ) { + return $arg_search->site_type; } + + $site_name = EE\Site\Utils\get_site_name(); + if ( $site_name ) { + if ( strpos( $url_path, '.' ) !== false ) { + $args[] = $site_name; + EE::error( + sprintf( + '%s is not a valid site-name. Did you mean `ee site %s`?', + $last_arg, + implode( ' ', $args ) + ) + ); + } + $type = Site::find( $site_name, [ 'site_type' ] )->site_type; + } + + return $type; } } From 253511755b7345fd18b48b70065f660ed5aae4fa Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Tue, 28 Aug 2018 17:45:37 +0530 Subject: [PATCH 32/81] add help hook for site-type and register html site-type Signed-off-by: Riddhesh Sanghvi --- site-command.php | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/site-command.php b/site-command.php index 8a10588b..a36c10c5 100644 --- a/site-command.php +++ b/site-command.php @@ -1,6 +1,8 @@ get_args(); + $args = $all_args[0]; + $assoc_args = $all_args[1]; + + if ( isset( $args[1] ) && 'site' === $args[1] ) { + $site_types = Site_Command::get_site_types(); + if ( ! isset( $assoc_args['type'] ) ) { + EE::error( 'No `--type` passed.' ); + } + $type = $assoc_args['type']; + if ( isset( $site_types[ $type ] ) ) { + $callback = $site_types[ $type ]; + + $command = EE::get_root_command(); + $leaf_command = CommandFactory::create( 'site', $callback, $command ); + $command->add_subcommand( 'site', $leaf_command ); + } else { + $error = sprintf( + "'%s' is not a registered site type of 'ee site --type=%s'. See 'ee help site --type=%s' for available subcommands.", + $type, + $type, + $type + ); + EE::error( $error ); + } + } +} + EE::add_command( 'site', 'Site_Command' ); +EE::add_hook( 'before_invoke:help', 'Before_Help_Command' ); +Site_Command::add_site_type( 'html', 'EE\Site\Type\HTML' ); From a2cbf6a0ee4fae7dd1bb82f787c0dd015f6baf06 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Tue, 28 Aug 2018 18:04:02 +0530 Subject: [PATCH 33/81] Move template from core to site-command Signed-off-by: Riddhesh Sanghvi --- templates/global_docker_compose.yml.mustache | 54 ++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 templates/global_docker_compose.yml.mustache diff --git a/templates/global_docker_compose.yml.mustache b/templates/global_docker_compose.yml.mustache new file mode 100644 index 00000000..bb231c72 --- /dev/null +++ b/templates/global_docker_compose.yml.mustache @@ -0,0 +1,54 @@ +version: '3.5' + +services: + +{{#services}} + {{name}}: + container_name: {{container_name}} + image: {{image}} + {{#ports.0}} + ports: + {{#ports}} + - "{{.}}" + {{/ports}} + {{/ports.0}} + {{#depends_on}} + depends_on: + - {{.}} + {{/depends_on}} + {{#restart}} + restart: {{.}} + {{/restart}} + {{#command}} + command: {{.}} + {{/command}} + {{#labels.0}} + labels: + {{#labels}} + - "{{.}}" + {{/labels}} + {{/labels.0}} + {{#volumes.0}} + volumes: + {{#volumes}} + - "{{.}}" + {{/volumes}} + {{/volumes.0}} + {{#environment.0}} + environment: + {{#environment}} + - {{.}} + {{/environment}} + {{/environment.0}} + {{#networks.0}} + networks: + {{#networks}} + - {{.}} + {{/networks}} + {{/networks.0}} +{{/services}} + +networks: + global-network: + external: + name: ee-global-network From b947d2470c599ee61cc76deb22291852f4a17e77 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Tue, 28 Aug 2018 18:05:01 +0530 Subject: [PATCH 34/81] Update template path Signed-off-by: Riddhesh Sanghvi --- src/site-utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/site-utils.php b/src/site-utils.php index df9825f5..e912cb02 100644 --- a/src/site-utils.php +++ b/src/site-utils.php @@ -151,7 +151,7 @@ function generate_global_docker_compose_yml( Filesystem $fs ) { ], ]; - $contents = EE\Utils\mustache_render( EE_ROOT . '/templates/global_docker_compose.yml.mustache', $data ); + $contents = EE\Utils\mustache_render( SITE_TEMPLATE_ROOT . '/global_docker_compose.yml.mustache', $data ); $fs->dumpFile( EE_CONF_ROOT . '/docker-compose.yml', $contents ); } From 81e5159ee130e449d6a7d174d8cdb86bf46a2a60 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Tue, 28 Aug 2018 18:07:20 +0530 Subject: [PATCH 35/81] Update namespace and filenames Signed-off-by: Riddhesh Sanghvi --- src/{Site_Docker.php => Docker_Compose_Generator.php} | 3 ++- src/HTML.php | 2 +- src/Site_Command.php | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) rename src/{Site_Docker.php => Docker_Compose_Generator.php} (96%) diff --git a/src/Site_Docker.php b/src/Docker_Compose_Generator.php similarity index 96% rename from src/Site_Docker.php rename to src/Docker_Compose_Generator.php index fe5cfb2b..a60ec648 100644 --- a/src/Site_Docker.php +++ b/src/Docker_Compose_Generator.php @@ -1,8 +1,9 @@ site['type']; - $site_docker = new Site_Docker(); + $site_docker = new Docker_Compose_Generator(); $docker_compose_content = $site_docker->generate_docker_compose_yml( $filter ); $default_conf_content = $default_conf_content = EE\Utils\mustache_render( SITE_TEMPLATE_ROOT . '/config/nginx/default.conf.mustache', [ 'server_name' => $this->site['url'] ] ); diff --git a/src/Site_Command.php b/src/Site_Command.php index 07a600e5..758a469e 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -1,7 +1,7 @@ Date: Tue, 28 Aug 2018 18:14:57 +0530 Subject: [PATCH 36/81] Update namespace and filenames Signed-off-by: Riddhesh Sanghvi --- src/HTML.php | 2 +- src/{Docker_Compose_Generator.php => Site_HTML_Docker.php} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/{Docker_Compose_Generator.php => Site_HTML_Docker.php} (98%) diff --git a/src/HTML.php b/src/HTML.php index 38c52f41..e169e1da 100644 --- a/src/HTML.php +++ b/src/HTML.php @@ -168,7 +168,7 @@ private function configure_site_files() { $filter = []; $filter[] = $this->site['type']; - $site_docker = new Docker_Compose_Generator(); + $site_docker = new Site_HTML_Docker(); $docker_compose_content = $site_docker->generate_docker_compose_yml( $filter ); $default_conf_content = $default_conf_content = EE\Utils\mustache_render( SITE_TEMPLATE_ROOT . '/config/nginx/default.conf.mustache', [ 'server_name' => $this->site['url'] ] ); diff --git a/src/Docker_Compose_Generator.php b/src/Site_HTML_Docker.php similarity index 98% rename from src/Docker_Compose_Generator.php rename to src/Site_HTML_Docker.php index a60ec648..42c5e357 100644 --- a/src/Docker_Compose_Generator.php +++ b/src/Site_HTML_Docker.php @@ -3,7 +3,7 @@ namespace EE\Site\Type; use function \EE\Utils\mustache_render; -class Docker_Compose_Generator { +class Site_HTML_Docker { /** * Generate docker-compose.yml according to requirement. From b8ff0f0bb0ffc5f6873f1a7c1e600f466624fefd Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Tue, 28 Aug 2018 20:15:52 +0530 Subject: [PATCH 37/81] Load site utility function file Signed-off-by: Riddhesh Sanghvi --- site-command.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/site-command.php b/site-command.php index a36c10c5..88482c5d 100644 --- a/site-command.php +++ b/site-command.php @@ -15,6 +15,9 @@ require_once $autoload; } +// Load utility functions +require_once 'src/site-utils.php'; + function Before_Help_Command() { $all_args = EE::get_runner()->get_args(); From 2976ebe1adec13aaa718633b3a58c10b2292a337 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Tue, 28 Aug 2018 20:17:47 +0530 Subject: [PATCH 38/81] Add type namespace in shutdownhandler and letsencrypt class Signed-off-by: Riddhesh Sanghvi --- src/Shutdown_Handler.php | 3 ++- src/Site_HTML_Docker.php | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Shutdown_Handler.php b/src/Shutdown_Handler.php index 2df3c30e..7a7bdebf 100644 --- a/src/Shutdown_Handler.php +++ b/src/Shutdown_Handler.php @@ -1,5 +1,6 @@ getMethod( 'shutDownFunction' ); $method->setAccessible( true ); $method->invoke( $site_command[0] ); diff --git a/src/Site_HTML_Docker.php b/src/Site_HTML_Docker.php index 42c5e357..8ce8dfc2 100644 --- a/src/Site_HTML_Docker.php +++ b/src/Site_HTML_Docker.php @@ -13,7 +13,7 @@ class Site_HTML_Docker { * @return String docker-compose.yml content string. */ public function generate_docker_compose_yml( array $filters = [] ) { - $img_versions = EE\Utils\get_image_versions(); + $img_versions = \EE\Utils\get_image_versions(); $base = []; $restart_default = [ 'name' => 'always' ]; From a7382dfad9cf2eac188582e0346d289b668c70f5 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Tue, 28 Aug 2018 20:18:22 +0530 Subject: [PATCH 39/81] Remove unnecessary namespace Signed-off-by: Riddhesh Sanghvi --- src/Site_Command.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Site_Command.php b/src/Site_Command.php index 758a469e..636454d6 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -1,6 +1,5 @@ Date: Tue, 28 Aug 2018 20:18:48 +0530 Subject: [PATCH 40/81] Add type namespace to Abstract class Signed-off-by: Riddhesh Sanghvi --- src/class-ee-site.php | 119 +++++++++++++++++++++--------------------- 1 file changed, 60 insertions(+), 59 deletions(-) diff --git a/src/class-ee-site.php b/src/class-ee-site.php index 1dcbae7a..db3ce914 100644 --- a/src/class-ee-site.php +++ b/src/class-ee-site.php @@ -1,5 +1,6 @@ site_url ); + \EE::log( $site->site_url ); } } else { $result = array_map( @@ -95,12 +96,12 @@ function ( $site ) { }, $sites ); - $formatter = new EE\Formatter( $assoc_args, [ 'site', 'status' ] ); + $formatter = new \EE\Formatter( $assoc_args, [ 'site', 'status' ] ); $formatter->display_items( $result ); } - EE\Utils\delem_log( 'site list end' ); + \EE\Utils\delem_log( 'site list end' ); } @@ -117,11 +118,11 @@ function ( $site ) { */ public function delete( $args, $assoc_args ) { - EE\Utils\delem_log( 'site delete start' ); + \EE\Utils\delem_log( 'site delete start' ); $this->populate_site_info( $args ); - EE::confirm( sprintf( 'Are you sure you want to delete %s?', $this->site['url'] ), $assoc_args ); + \EE::confirm( sprintf( 'Are you sure you want to delete %s?', $this->site['url'] ), $assoc_args ); $this->delete_site( 5, $this->site['url'], $this->site['root'] ); - EE\Utils\delem_log( 'site delete end' ); + \EE\Utils\delem_log( 'site delete end' ); } /** @@ -141,12 +142,12 @@ protected function delete_site( $level, $site_name, $site_root ) { $this->fs = new Filesystem(); $proxy_type = EE_PROXY_TYPE; if ( $level >= 3 ) { - if ( EE::docker()::docker_compose_down( $site_root ) ) { - EE::log( "[$site_name] Docker Containers removed." ); + if ( \EE::docker()::docker_compose_down( $site_root ) ) { + \EE::log( "[$site_name] Docker Containers removed." ); } else { - EE::exec( "docker rm -f $(docker ps -q -f=label=created_by=EasyEngine -f=label=site_name=$site_name)" ); + \EE::exec( "docker rm -f $(docker ps -q -f=label=created_by=EasyEngine -f=label=site_name=$site_name)" ); if ( $level > 3 ) { - EE::warning( 'Error in removing docker containers.' ); + \EE::warning( 'Error in removing docker containers.' ); } } } @@ -155,10 +156,10 @@ protected function delete_site( $level, $site_name, $site_root ) { try { $this->fs->remove( $site_root ); } catch ( Exception $e ) { - EE::debug( $e ); - EE::error( 'Could not remove site root. Please check if you have sufficient rights.' ); + \EE::debug( $e ); + \EE::error( 'Could not remove site root. Please check if you have sufficient rights.' ); } - EE::log( "[$site_name] site root removed." ); + \EE::log( "[$site_name] site root removed." ); } $config_file_path = EE_CONF_ROOT . '/nginx/conf.d/' . $site_name . '-redirect.conf'; @@ -167,15 +168,15 @@ protected function delete_site( $level, $site_name, $site_root ) { try { $this->fs->remove( $config_file_path ); } catch ( Exception $e ) { - EE::debug( $e ); - EE::error( 'Could not remove site redirection file. Please check if you have sufficient rights.' ); + \EE::debug( $e ); + \EE::error( 'Could not remove site redirection file. Please check if you have sufficient rights.' ); } } if ( $level > 4 ) { if ( $this->ssl ) { - EE::log( 'Removing ssl certs.' ); + \EE::log( 'Removing ssl certs.' ); $crt_file = EE_CONF_ROOT . "/nginx/certs/$site_name.crt"; $key_file = EE_CONF_ROOT . "/nginx/certs/$site_name.key"; $conf_certs = EE_CONF_ROOT . "/acme-conf/certs/$site_name"; @@ -185,17 +186,17 @@ protected function delete_site( $level, $site_name, $site_root ) { try { $this->fs->remove( $cert_files ); } catch ( Exception $e ) { - EE::warning( $e ); + \EE::warning( $e ); } } if ( Site::find( $site_name )->delete() ) { - EE::log( 'Removed database entry.' ); + \EE::log( 'Removed database entry.' ); } else { - EE::error( 'Could not remove the database entry' ); + \EE::error( 'Could not remove the database entry' ); } } - EE::log( "Site $site_name deleted." ); + \EE::log( "Site $site_name deleted." ); } /** @@ -211,26 +212,26 @@ protected function delete_site( $level, $site_name, $site_root ) { */ public function up( $args, $assoc_args ) { - EE\Utils\delem_log( 'site enable start' ); - $force = EE\Utils\get_flag_value( $assoc_args, 'force' ); + \EE\Utils\delem_log( 'site enable start' ); + $force = \EE\Utils\get_flag_value( $assoc_args, 'force' ); $args = EE\SiteUtils\auto_site_name( $args, 'site', __FUNCTION__ ); $this->populate_site_info( $args ); $site = Site::find( $this->site['url'] ); if ( $site->site_enabled && ! $force ) { - EE::error( sprintf( '%s is already enabled!', $site->site_url ) ); + \EE::error( sprintf( '%s is already enabled!', $site->site_url ) ); } - EE::log( sprintf( 'Enabling site %s.', $site->site_url ) ); + \EE::log( sprintf( 'Enabling site %s.', $site->site_url ) ); - if ( EE::docker()::docker_compose_up( $this->site['root'] ) ) { + if ( \EE::docker()::docker_compose_up( $this->site['root'] ) ) { $site->site_enabled = 1; $site->save(); - EE::success( "Site $site->site_url enabled." ); + \EE::success( "Site $site->site_url enabled." ); } else { - EE::error( sprintf( 'There was error in enabling %s. Please check logs.', $site->site_url ) ); + \EE::error( sprintf( 'There was error in enabling %s. Please check logs.', $site->site_url ) ); } - EE\Utils\delem_log( 'site enable end' ); + \EE\Utils\delem_log( 'site enable end' ); } /** @@ -243,23 +244,23 @@ public function up( $args, $assoc_args ) { */ public function down( $args, $assoc_args ) { - EE\Utils\delem_log( 'site disable start' ); + \EE\Utils\delem_log( 'site disable start' ); $args = EE\SiteUtils\auto_site_name( $args, 'site', __FUNCTION__ ); $this->populate_site_info( $args ); $site = Site::find($this->site['url']); - EE::log( sprintf( 'Disabling site %s.', $site->site_url ) ); + \EE::log( sprintf( 'Disabling site %s.', $site->site_url ) ); - if ( EE::docker()::docker_compose_down( $this->site['root'] ) ) { + if ( \EE::docker()::docker_compose_down( $this->site['root'] ) ) { $site->site_enabled = 0; $site->save(); - EE::success( sprintf( 'Site %s disabled.', $this->site['url'] ) ); + \EE::success( sprintf( 'Site %s disabled.', $this->site['url'] ) ); } else { - EE::error( sprintf( 'There was error in disabling %s. Please check logs.', $this->site['url'] ) ); + \EE::error( sprintf( 'There was error in disabling %s. Please check logs.', $this->site['url'] ) ); } - EE\Utils\delem_log( 'site disable end' ); + \EE\Utils\delem_log( 'site disable end' ); } /** @@ -277,9 +278,9 @@ public function down( $args, $assoc_args ) { */ public function restart( $args, $assoc_args, $whitelisted_containers = [] ) { - EE\Utils\delem_log( 'site restart start' ); + \EE\Utils\delem_log( 'site restart start' ); $args = EE\SiteUtils\auto_site_name( $args, 'site', __FUNCTION__ ); - $all = EE\Utils\get_flag_value( $assoc_args, 'all' ); + $all = \EE\Utils\get_flag_value( $assoc_args, 'all' ); $no_service_specified = count( $assoc_args ) === 0; $this->populate_site_info( $args ); @@ -295,7 +296,7 @@ public function restart( $args, $assoc_args, $whitelisted_containers = [] ) { foreach ( $containers as $container ) { EE\Siteutils\run_compose_command( 'restart', $container ); } - EE\Utils\delem_log( 'site restart stop' ); + \EE\Utils\delem_log( 'site restart stop' ); } /** @@ -314,9 +315,9 @@ public function restart( $args, $assoc_args, $whitelisted_containers = [] ) { */ public function reload( $args, $assoc_args, $whitelisted_containers = [], $reload_commands = [] ) { - EE\Utils\delem_log( 'site reload start' ); + \EE\Utils\delem_log( 'site reload start' ); $args = EE\SiteUtils\auto_site_name( $args, 'site', __FUNCTION__ ); - $all = EE\Utils\get_flag_value( $assoc_args, 'all' ); + $all = \EE\Utils\get_flag_value( $assoc_args, 'all' ); if ( !array_key_exists( 'nginx', $reload_commands ) ) { $reload_commands['nginx'] = 'nginx sh -c \'nginx -t && service openresty reload\''; } @@ -331,7 +332,7 @@ public function reload( $args, $assoc_args, $whitelisted_containers = [], $reloa } else { $this->reload_services( array_keys( $assoc_args ), $reload_commands ); } - EE\Utils\delem_log( 'site reload stop' ); + \EE\Utils\delem_log( 'site reload stop' ); } /** @@ -371,7 +372,7 @@ protected function inherit_certs( $site_name ) { } // We don't have to do anything now as nginx-proxy handles everything for us. - EE::success( 'Inherited certs from parent' ); + \EE::success( 'Inherited certs from parent' ); } /** @@ -385,18 +386,18 @@ protected function inherit_certs( $site_name ) { * @throws \EE\ExitException If --ssl flag has unrecognized value */ protected function init_ssl( $site_name, $site_root, $ssl_type, $wildcard = false ) { - EE::debug( 'Starting SSL procedure' ); + \EE::debug( 'Starting SSL procedure' ); if ( 'le' === $ssl_type ) { - EE::debug( 'Initializing LE' ); + \EE::debug( 'Initializing LE' ); $this->init_le( $site_name, $site_root, $wildcard ); } elseif ( 'inherit' === $ssl_type ) { if ( $wildcard ) { - EE::error( 'Cannot use --wildcard with --ssl=inherit', false ); + \EE::error( 'Cannot use --wildcard with --ssl=inherit', false ); } - EE::debug( 'Inheriting certs' ); + \EE::debug( 'Inheriting certs' ); $this->inherit_certs( $site_name ); } else { - EE::error( "Unrecognized value in --ssl flag: $ssl_type" ); + \EE::error( "Unrecognized value in --ssl flag: $ssl_type" ); } } @@ -408,14 +409,14 @@ protected function init_ssl( $site_name, $site_root, $ssl_type, $wildcard = fals * @param bool $wildcard SSL with wildcard or not. */ protected function init_le( $site_name, $site_root, $wildcard = false ) { - EE::debug( "Wildcard in init_le: $wildcard" ); + \EE::debug( "Wildcard in init_le: $wildcard" ); $this->site['url'] = $site_name; $this->site['root'] = $site_root; $this->wildcard = $wildcard; $client = new Site_Letsencrypt(); - $this->le_mail = EE::get_runner()->config['le-mail'] ?? EE::input( 'Enter your mail id: ' ); - EE::get_runner()->ensure_present_in_config( 'le-mail', $this->le_mail ); + $this->le_mail = \EE::get_runner()->config['le-mail'] ?? \EE::input( 'Enter your mail id: ' ); + \EE::get_runner()->ensure_present_in_config( 'le-mail', $this->le_mail ); if ( ! $client->register( $this->le_mail ) ) { $this->ssl = null; @@ -493,10 +494,10 @@ public function le( $args = [], $assoc_args = [] ) { } if ( !isset( $this->le_mail ) ) { - $this->le_mail = EE::get_config( 'le-mail' ) ?? EE::input( 'Enter your mail id: ' ); + $this->le_mail = \EE::get_config( 'le-mail' ) ?? \EE::input( 'Enter your mail id: ' ); } - $force = EE\Utils\get_flag_value( $assoc_args, 'force' ); + $force = \EE\Utils\get_flag_value( $assoc_args, 'force' ); $domains = $this->get_cert_domains( $this->site['url'], $this->wildcard ); $client = new Site_Letsencrypt(); @@ -511,7 +512,7 @@ public function le( $args = [], $assoc_args = [] ) { if ( ! $this->wildcard ) { $client->cleanup( $this->site['root'] ); } - EE::launch( 'docker exec ee-nginx-proxy sh -c "/app/docker-entrypoint.sh /usr/local/bin/docker-gen /app/nginx.tmpl /etc/nginx/conf.d/default.conf; /usr/sbin/nginx -s reload"' ); + \EE::launch( 'docker exec ee-nginx-proxy sh -c "/app/docker-entrypoint.sh /usr/local/bin/docker-gen /app/nginx.tmpl /etc/nginx/conf.d/default.conf; /usr/sbin/nginx -s reload"' ); } /** @@ -519,7 +520,7 @@ public function le( $args = [], $assoc_args = [] ) { */ private function populate_site_info( $args ) { - $this->site['url'] = EE\Utils\remove_trailing_slash( $args[0] ); + $this->site['url'] = \EE\Utils\remove_trailing_slash( $args[0] ); $site = Site::find( $this->site['url'] ); if ( $site ) { @@ -530,7 +531,7 @@ private function populate_site_info( $args ) { $this->ssl = $site->site_ssl; $this->wildcard = $site->site_ssl_wildcard; } else { - EE::error( sprintf( 'Site %s does not exist.', $this->site['url'] ) ); + \EE::error( sprintf( 'Site %s does not exist.', $this->site['url'] ) ); } } From ebd3eff308be30a9c8cc0ac0b748b1c1a76beb42 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Tue, 28 Aug 2018 20:19:16 +0530 Subject: [PATCH 41/81] Add type namespace to letsencrypt class Signed-off-by: Riddhesh Sanghvi --- src/Site_Letsencrypt.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Site_Letsencrypt.php b/src/Site_Letsencrypt.php index 9c396b94..fb2afb39 100644 --- a/src/Site_Letsencrypt.php +++ b/src/Site_Letsencrypt.php @@ -1,5 +1,6 @@ Date: Tue, 28 Aug 2018 20:25:59 +0530 Subject: [PATCH 42/81] Update EE usage to \EE acc to new namespace Signed-off-by: Riddhesh Sanghvi --- src/HTML.php | 87 ++++++++++++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/src/HTML.php b/src/HTML.php index e169e1da..f55dc371 100644 --- a/src/HTML.php +++ b/src/HTML.php @@ -14,6 +14,7 @@ */ namespace EE\Site\Type; +use \EE\Model\Site; use \Symfony\Component\Filesystem\Filesystem; @@ -25,7 +26,7 @@ class HTML extends EE_Site_Command { private $site; /** - * @var object $docker Object to access `EE::docker()` functions. + * @var object $docker Object to access `\EE::docker()` functions. */ private $docker; @@ -68,8 +69,8 @@ public function __construct() { pcntl_signal( SIGINT, [ $this, "rollback" ] ); $shutdown_handler = new Shutdown_Handler(); register_shutdown_function( [ $shutdown_handler, "cleanup" ], [ &$this ] ); - $this->docker = EE::docker(); - $this->logger = EE::get_file_logger()->withName( 'site_command' ); + $this->docker = \EE::docker(); + $this->logger = \EE::get_file_logger()->withName( 'site_command' ); $this->fs = new Filesystem(); } @@ -94,30 +95,30 @@ public function __construct() { */ public function create( $args, $assoc_args ) { - EE\Utils\delem_log( 'site create start' ); - EE::warning( 'This is a beta version. Please don\'t use it in production.' ); + \EE\Utils\delem_log( 'site create start' ); + \EE::warning( 'This is a beta version. Please don\'t use it in production.' ); $this->logger->debug( 'args:', $args ); $this->logger->debug( 'assoc_args:', empty( $assoc_args ) ? [ 'NULL' ] : $assoc_args ); - $this->site['url'] = strtolower( EE\Utils\remove_trailing_slash( $args[0] ) ); - $this->site['type'] = EE\Utils\get_flag_value( $assoc_args, 'type', 'html' ); + $this->site['url'] = strtolower( \EE\Utils\remove_trailing_slash( $args[0] ) ); + $this->site['type'] = \EE\Utils\get_flag_value( $assoc_args, 'type', 'html' ); if ( 'html' !== $this->site['type'] ) { - EE::error( sprintf( 'Invalid site-type: %s', $this->site['type'] ) ); + \EE::error( sprintf( 'Invalid site-type: %s', $this->site['type'] ) ); } if ( Site::find( $this->site['url'] ) ) { - EE::error( sprintf( "Site %1\$s already exists. If you want to re-create it please delete the older one using:\n`ee site delete %1\$s`", $this->site['url'] ) ); + \EE::error( sprintf( "Site %1\$s already exists. If you want to re-create it please delete the older one using:\n`ee site delete %1\$s`", $this->site['url'] ) ); } - $this->ssl = EE\Utils\get_flag_value( $assoc_args, 'ssl' ); - $this->ssl_wildcard = EE\Utils\get_flag_value( $assoc_args, 'wildcard' ); - $this->skip_chk = EE\Utils\get_flag_value( $assoc_args, 'skip-status-check' ); + $this->ssl = \EE\Utils\get_flag_value( $assoc_args, 'ssl' ); + $this->ssl_wildcard = \EE\Utils\get_flag_value( $assoc_args, 'wildcard' ); + $this->skip_chk = \EE\Utils\get_flag_value( $assoc_args, 'skip-status-check' ); - EE\Site\Utils\init_checks(); + \EE\Site\Utils\init_checks(); - EE::log( 'Configuring project.' ); + \EE::log( 'Configuring project.' ); $this->create_site(); - EE\Utils\delem_log( 'site create end' ); + \EE\Utils\delem_log( 'site create end' ); } /** @@ -128,9 +129,9 @@ public function create( $args, $assoc_args ) { */ public function info( $args, $assoc_args ) { - EE\Utils\delem_log( 'site info start' ); + \EE\Utils\delem_log( 'site info start' ); if ( ! isset( $this->site['url'] ) ) { - $args = EE\Site\Utils\auto_site_name( $args, 'site', __FUNCTION__ ); + $args = \EE\Site\Utils\auto_site_name( $args, 'site', __FUNCTION__ ); $this->populate_site_info( $args ); } $ssl = $this->ssl ? 'Enabled' : 'Not Enabled'; @@ -145,9 +146,9 @@ public function info( $args, $assoc_args ) { $info[] = [ 'SSL Wildcard', $this->ssl_wildcard ? 'Yes': 'No' ]; } - EE\Utils\format_table( $info ); + \EE\Utils\format_table( $info ); - EE\Utils\delem_log( 'site info end' ); + \EE\Utils\delem_log( 'site info end' ); } @@ -163,21 +164,21 @@ private function configure_site_files() { $site_src_dir = $this->site['root'] . '/app/src'; $process_user = posix_getpwuid( posix_geteuid() ); - EE::log( sprintf( 'Creating site %s.', $this->site['url'] ) ); - EE::log( 'Copying configuration files.' ); + \EE::log( sprintf( 'Creating site %s.', $this->site['url'] ) ); + \EE::log( 'Copying configuration files.' ); $filter = []; $filter[] = $this->site['type']; $site_docker = new Site_HTML_Docker(); $docker_compose_content = $site_docker->generate_docker_compose_yml( $filter ); - $default_conf_content = $default_conf_content = EE\Utils\mustache_render( SITE_TEMPLATE_ROOT . '/config/nginx/default.conf.mustache', [ 'server_name' => $this->site['url'] ] ); + $default_conf_content = $default_conf_content = \EE\Utils\mustache_render( SITE_TEMPLATE_ROOT . '/config/nginx/default.conf.mustache', [ 'server_name' => $this->site['url'] ] ); $env_data = [ 'virtual_host' => $this->site['url'], 'user_id' => $process_user['uid'], 'group_id' => $process_user['gid'], ]; - $env_content = EE\Utils\mustache_render( SITE_TEMPLATE_ROOT . '/config/.env.mustache', $env_data ); + $env_content = \EE\Utils\mustache_render( SITE_TEMPLATE_ROOT . '/config/.env.mustache', $env_data ); try { $this->fs->dumpFile( $site_docker_yml, $docker_compose_content ); @@ -190,11 +191,11 @@ private function configure_site_files() { 'version' => 'v' . EE_VERSION, 'site_src_root' => $this->site['root'] . '/app/src', ]; - $index_html = EE\Utils\mustache_render( SITE_TEMPLATE_ROOT . '/index.html.mustache', $index_data ); + $index_html = \EE\Utils\mustache_render( SITE_TEMPLATE_ROOT . '/index.html.mustache', $index_data ); $this->fs->mkdir( $site_src_dir ); $this->fs->dumpFile( $site_src_dir . '/index.html', $index_html ); - EE::success( 'Configuration files copied.' ); + \EE::success( 'Configuration files copied.' ); } catch ( Exception $e ) { $this->catch_clean( $e ); } @@ -208,16 +209,16 @@ private function create_site() { $this->site['root'] = WEBROOT . $this->site['url']; $this->level = 1; try { - EE\Site\Utils\create_site_root( $this->site['root'], $this->site['url'] ); + \EE\Site\Utils\create_site_root( $this->site['root'], $this->site['url'] ); $this->level = 3; $this->configure_site_files(); - EE\Site\Utils\start_site_containers( $this->site['root'] ); + \EE\Site\Utils\start_site_containers( $this->site['root'] ); - EE\Site\Utils\create_etc_hosts_entry( $this->site['url'] ); + \EE\Site\Utils\create_etc_hosts_entry( $this->site['url'] ); if ( ! $this->skip_chk ) { $this->level = 4; - EE\Site\Utils\site_status_check( $this->site['url'] ); + \EE\Site\Utils\site_status_check( $this->site['url'] ); } /* @@ -230,13 +231,13 @@ private function create_site() { * We add redirection config two times in case of ssl as we need http redirection * when certs are being requested and http+https redirection after we have certs. */ - EE\Site\Utils\add_site_redirects( $this->site['url'], false, 'inherit' === $this->ssl ); - EE\Site\Utils\reload_proxy_configuration(); + \EE\Site\Utils\add_site_redirects( $this->site['url'], false, 'inherit' === $this->ssl ); + \EE\Site\Utils\reload_proxy_configuration(); if ( $this->ssl ) { $this->init_ssl( $this->site['url'], $this->site['root'], $this->ssl, $this->ssl_wildcard ); - EE\Site\Utils\add_site_redirects( $this->site['url'], true, 'inherit' === $this->ssl ); - EE\Site\Utils\reload_proxy_configuration(); + \EE\Site\Utils\add_site_redirects( $this->site['url'], true, 'inherit' === $this->ssl ); + \EE\Site\Utils\reload_proxy_configuration(); } } catch ( Exception $e ) { $this->catch_clean( $e ); @@ -265,7 +266,7 @@ private function create_site_db_entry() { try { if ( $site ) { - EE::log( 'Site entry created.' ); + \EE::log( 'Site entry created.' ); } else { throw new Exception( 'Error creating site entry in database.' ); } @@ -279,7 +280,7 @@ private function create_site_db_entry() { */ private function populate_site_info( $args ) { - $this->site['url'] = EE\Utils\remove_trailing_slash( $args[0] ); + $this->site['url'] = \EE\Utils\remove_trailing_slash( $args[0] ); $site = Site::find( $this->site['url'] ); @@ -289,7 +290,7 @@ private function populate_site_info( $args ) { $this->ssl = $site->site_ssl; $this->ssl_wildcard = $site->site_ssl_wildcard; } else { - EE::error( sprintf( 'Site %s does not exist.', $this->site['url'] ) ); + \EE::error( sprintf( 'Site %s does not exist.', $this->site['url'] ) ); } } @@ -316,11 +317,11 @@ public function reload( $args, $assoc_args, $whitelisted_containers = [], $reloa */ private function catch_clean( $e ) { - EE\Utils\delem_log( 'site cleanup start' ); - EE::warning( $e->getMessage() ); - EE::warning( 'Initiating clean-up.' ); + \EE\Utils\delem_log( 'site cleanup start' ); + \EE::warning( $e->getMessage() ); + \EE::warning( 'Initiating clean-up.' ); $this->delete_site( $this->level, $this->site['url'], $this->site['root'] ); - EE\Utils\delem_log( 'site cleanup end' ); + \EE\Utils\delem_log( 'site cleanup end' ); exit; } @@ -329,11 +330,11 @@ private function catch_clean( $e ) { */ private function rollback() { - EE::warning( 'Exiting gracefully after rolling back. This may take some time.' ); + \EE::warning( 'Exiting gracefully after rolling back. This may take some time.' ); if ( $this->level > 0 ) { $this->delete_site( $this->level, $this->site['url'], $this->site['root'] ); } - EE::success( 'Rollback complete. Exiting now.' ); + \EE::success( 'Rollback complete. Exiting now.' ); exit; } @@ -344,7 +345,7 @@ private function shutDownFunction() { $error = error_get_last(); if ( isset( $error ) && $error['type'] === E_ERROR ) { - EE::warning( 'An Error occurred. Initiating clean-up.' ); + \EE::warning( 'An Error occurred. Initiating clean-up.' ); $this->logger->error( 'Type: ' . $error['type'] ); $this->logger->error( 'Message: ' . $error['message'] ); $this->logger->error( 'File: ' . $error['file'] ); From a8af7f180b93e4b0f9b2460da33912221333c50a Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Tue, 28 Aug 2018 21:52:06 +0530 Subject: [PATCH 43/81] Update getting of args in help and set default type Signed-off-by: Riddhesh Sanghvi --- site-command.php | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/site-command.php b/site-command.php index 88482c5d..a672fcf8 100644 --- a/site-command.php +++ b/site-command.php @@ -18,18 +18,17 @@ // Load utility functions require_once 'src/site-utils.php'; -function Before_Help_Command() { +function Before_Help_Command( $args, $assoc_args ) { - $all_args = EE::get_runner()->get_args(); - $args = $all_args[0]; - $assoc_args = $all_args[1]; - - if ( isset( $args[1] ) && 'site' === $args[1] ) { + if ( isset( $args[0] ) && 'site' === $args[0] ) { $site_types = Site_Command::get_site_types(); - if ( ! isset( $assoc_args['type'] ) ) { - EE::error( 'No `--type` passed.' ); + if ( isset( $assoc_args['type'] ) ) { + $type = $assoc_args['type']; + } else { + //TODO: get from config. + $type = 'html'; } - $type = $assoc_args['type']; + if ( isset( $site_types[ $type ] ) ) { $callback = $site_types[ $type ]; From 5df0eafcc1afbc1cf3feb2c9f2dd480f002fc9e4 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Tue, 28 Aug 2018 21:56:01 +0530 Subject: [PATCH 44/81] Update EE usage to \EE for letsencrypt class Signed-off-by: Riddhesh Sanghvi --- src/Site_Letsencrypt.php | 108 +++++++++++++++++++-------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/src/Site_Letsencrypt.php b/src/Site_Letsencrypt.php index fb2afb39..56e426d2 100644 --- a/src/Site_Letsencrypt.php +++ b/src/Site_Letsencrypt.php @@ -59,15 +59,15 @@ function __construct() { private function setAcmeClient() { if ( ! $this->repository->hasAccountKeyPair() ) { - EE::debug( 'No account key pair was found, generating one.' ); - EE::debug( 'Generating a key pair' ); + \EE::debug( 'No account key pair was found, generating one.' ); + \EE::debug( 'Generating a key pair' ); $keygen = new KeyPairGenerator(); $accountKeyPair = $keygen->generateKeyPair(); - EE::debug( 'Key pair generated, storing' ); + \EE::debug( 'Key pair generated, storing' ); $this->repository->storeAccountKeyPair( $accountKeyPair ); } else { - EE::debug( 'Loading account keypair' ); + \EE::debug( 'Loading account keypair' ); $accountKeyPair = $this->repository->loadAccountKeyPair(); } @@ -114,12 +114,12 @@ public function register( $email ) { $this->client->registerAccount( null, $email ); } catch ( Exception $e ) { - EE::warning( $e->getMessage() ); - EE::warning( 'It seems you\'re in local environment or there is some issue with network, please check logs. Skipping letsencrypt.' ); + \EE::warning( $e->getMessage() ); + \EE::warning( 'It seems you\'re in local environment or there is some issue with network, please check logs. Skipping letsencrypt.' ); return false; } - EE::debug( "Account with email id: $email registered successfully!" ); + \EE::debug( "Account with email id: $email registered successfully!" ); return true; } @@ -130,8 +130,8 @@ public function authorize( Array $domains, $site_root, $wildcard = false ) { $order = $this->client->requestOrder( $domains ); } catch ( Exception $e ) { - EE::warning( $e->getMessage() ); - EE::warning( 'It seems you\'re in local environment or using non-public domain, please check logs. Skipping letsencrypt.' ); + \EE::warning( $e->getMessage() ); + \EE::warning( 'It seems you\'re in local environment or using non-public domain, please check logs. Skipping letsencrypt.' ); return false; } @@ -142,16 +142,16 @@ public function authorize( Array $domains, $site_root, $wildcard = false ) { foreach ( $authorizationChallenges as $candidate ) { if ( $solver->supports( $candidate ) ) { $authorizationChallenge = $candidate; - EE::debug( 'Authorization challenge supported by solver. Solver: ' . $solverName . ' Challenge: ' . $candidate->getType() ); + \EE::debug( 'Authorization challenge supported by solver. Solver: ' . $solverName . ' Challenge: ' . $candidate->getType() ); break; } // Should not get here as we are handling it. - EE::debug( 'Authorization challenge not supported by solver. Solver: ' . $solverName . ' Challenge: ' . $candidate->getType() ); + \EE::debug( 'Authorization challenge not supported by solver. Solver: ' . $solverName . ' Challenge: ' . $candidate->getType() ); } if ( null === $authorizationChallenge ) { throw new ChallengeNotSupportedException(); } - EE::debug( 'Storing authorization challenge. Domain: ' . $domainKey . ' Challenge: ' . print_r( $authorizationChallenge->toArray(), true ) ); + \EE::debug( 'Storing authorization challenge. Domain: ' . $domainKey . ' Challenge: ' . print_r( $authorizationChallenge->toArray(), true ) ); $this->repository->storeDomainAuthorizationChallenge( $domainKey, $authorizationChallenge ); $authorizationChallengesToSolve[] = $authorizationChallenge; @@ -159,16 +159,16 @@ public function authorize( Array $domains, $site_root, $wildcard = false ) { /** @var AuthorizationChallenge $authorizationChallenge */ foreach ( $authorizationChallengesToSolve as $authorizationChallenge ) { - EE::debug( 'Solving authorization challenge: Domain: ' . $authorizationChallenge->getDomain() . ' Challenge: ' . print_r( $authorizationChallenge->toArray(), true ) ); + \EE::debug( 'Solving authorization challenge: Domain: ' . $authorizationChallenge->getDomain() . ' Challenge: ' . print_r( $authorizationChallenge->toArray(), true ) ); $solver->solve( $authorizationChallenge ); if ( ! $wildcard ) { $token = $authorizationChallenge->toArray()['token']; $payload = $authorizationChallenge->toArray()['payload']; - EE::launch( "mkdir -p $site_root/app/src/.well-known/acme-challenge/" ); - EE::debug( "Creating challange file $site_root/app/src/.well-known/acme-challenge/$token" ); + \EE::launch( "mkdir -p $site_root/app/src/.well-known/acme-challenge/" ); + \EE::debug( "Creating challange file $site_root/app/src/.well-known/acme-challenge/$token" ); file_put_contents( "$site_root/app/src/.well-known/acme-challenge/$token", $payload ); - EE::launch( "chown www-data: $site_root/app/src/.well-known/acme-challenge/$token" ); + \EE::launch( "chown www-data: $site_root/app/src/.well-known/acme-challenge/$token" ); } } @@ -178,7 +178,7 @@ public function authorize( Array $domains, $site_root, $wildcard = false ) { } public function check( Array $domains, $wildcard = false ) { - EE::debug( ('Starting check with solver ') . ($wildcard ? 'dns' : 'http') ); + \EE::debug( ('Starting check with solver ') . ($wildcard ? 'dns' : 'http') ); $solver = $wildcard ? new SimpleDnsSolver( null, new ConsoleOutput() ) : new SimpleHttpSolver(); $validator = new ChainValidator( [ @@ -190,7 +190,7 @@ public function check( Array $domains, $wildcard = false ) { $order = null; if ( $this->repository->hasCertificateOrder( $domains ) ) { $order = $this->repository->loadCertificateOrder( $domains ); - EE::debug( sprintf( 'Loading the authorization token for domains %s ...', implode( ', ', $domains ) ) ); + \EE::debug( sprintf( 'Loading the authorization token for domains %s ...', implode( ', ', $domains ) ) ); } $authorizationChallengeToCleanup = []; @@ -209,31 +209,31 @@ public function check( Array $domains, $wildcard = false ) { } } else { if ( ! $this->repository->hasDomainAuthorizationChallenge( $domain ) ) { - EE::error( "Domain: $domain not yet authorized/has not been started of with EasyEngine letsencrypt site creation." ); + \EE::error( "Domain: $domain not yet authorized/has not been started of with EasyEngine letsencrypt site creation." ); } $authorizationChallenge = $this->repository->loadDomainAuthorizationChallenge( $domain ); if ( ! $solver->supports( $authorizationChallenge ) ) { throw new ChallengeNotSupportedException(); } } - EE::debug( 'Challenge loaded.' ); + \EE::debug( 'Challenge loaded.' ); $authorizationChallenge = $this->client->reloadAuthorization( $authorizationChallenge ); if ( ! $authorizationChallenge->isValid() ) { - EE::debug( sprintf( 'Testing the challenge for domain %s', $domain ) ); + \EE::debug( sprintf( 'Testing the challenge for domain %s', $domain ) ); if ( ! $validator->isValid( $authorizationChallenge ) ) { - EE::warning( sprintf( 'Can not valid challenge for domain %s', $domain ) ); + \EE::warning( sprintf( 'Can not valid challenge for domain %s', $domain ) ); } - EE::debug( sprintf( 'Requesting authorization check for domain %s', $domain ) ); + \EE::debug( sprintf( 'Requesting authorization check for domain %s', $domain ) ); try { $this->client->challengeAuthorization( $authorizationChallenge ); } catch ( Exception $e ) { - EE::debug( $e->getMessage() ); - EE::warning( 'Challange Authorization failed. Check logs and check if your domain is pointed correctly to this server.' ); + \EE::debug( $e->getMessage() ); + \EE::warning( 'Challange Authorization failed. Check logs and check if your domain is pointed correctly to this server.' ); $site_name = isset( $domains[1] ) ? $domains[1] : $domains[0]; - EE::log( "Re-run `ee site le $site_name` after fixing the issue." ); + \EE::log( "Re-run `ee site le $site_name` after fixing the issue." ); return false; } @@ -241,7 +241,7 @@ public function check( Array $domains, $wildcard = false ) { } } - EE::log( 'The authorization check was successful!' ); + \EE::log( 'The authorization check was successful!' ); if ( $solver instanceof MultipleChallengesSolverInterface ) { $solver->cleanupAll( $authorizationChallengeToCleanup ); @@ -260,12 +260,12 @@ public function request( $domain, $altNames = [], $email, $force=false ) { // Certificate renewal if ( $this->hasValidCertificate( $domain, $alternativeNames ) ) { - EE::debug( "Certificate found for $domain, executing renewal" ); + \EE::debug( "Certificate found for $domain, executing renewal" ); return $this->executeRenewal( $domain, $alternativeNames, $force ); } - EE::debug( "No certificate found, executing first request for $domain" ); + \EE::debug( "No certificate found, executing first request for $domain" ); // Certificate first request return $this->executeFirstRequest( $domain, $alternativeNames, $email ); @@ -278,36 +278,36 @@ public function request( $domain, $altNames = [], $email, $force=false ) { * @param array $alternativeNames */ private function executeFirstRequest( $domain, array $alternativeNames, $email ) { - EE::log( 'Executing first request.' ); + \EE::log( 'Executing first request.' ); // Generate domain key pair $keygen = new KeyPairGenerator(); $domainKeyPair = $keygen->generateKeyPair(); $this->repository->storeDomainKeyPair( $domain, $domainKeyPair ); - EE::debug( "$domain Domain key pair generated and stored" ); + \EE::debug( "$domain Domain key pair generated and stored" ); $distinguishedName = $this->getOrCreateDistinguishedName( $domain, $alternativeNames, $email ); // TODO: ask them ;) - EE::debug( 'Distinguished name informations have been stored locally for this domain (they won\'t be asked on renewal).' ); + \EE::debug( 'Distinguished name informations have been stored locally for this domain (they won\'t be asked on renewal).' ); // Order $domains = array_merge( [ $domain ], $alternativeNames ); - EE::debug( sprintf( 'Loading the order related to the domains %s .', implode( ', ', $domains ) ) ); + \EE::debug( sprintf( 'Loading the order related to the domains %s .', implode( ', ', $domains ) ) ); if ( ! $this->repository->hasCertificateOrder( $domains ) ) { - EE::error( "$domain has not yet been authorized." ); + \EE::error( "$domain has not yet been authorized." ); } $order = $this->repository->loadCertificateOrder( $domains ); // Request - EE::log( sprintf( 'Requesting first certificate for domain %s.', $domain ) ); + \EE::log( sprintf( 'Requesting first certificate for domain %s.', $domain ) ); $csr = new CertificateRequest( $distinguishedName, $domainKeyPair ); $response = $this->client->finalizeOrder( $order, $csr ); - EE::log( 'Certificate received' ); + \EE::log( 'Certificate received' ); // Store $this->repository->storeDomainCertificate( $domain, $response->getCertificate() ); - EE::log( 'Certificate stored' ); + \EE::log( 'Certificate stored' ); // Post-generate actions $this->moveCertsToNginxProxy( $domain ); @@ -338,7 +338,7 @@ private function moveCertsToNginxProxy( string $domain ) { private function executeRenewal( $domain, array $alternativeNames, $force = false ) { try { // Check expiration date to avoid too much renewal - EE::log( "Loading current certificate for $domain" ); + \EE::log( "Loading current certificate for $domain" ); $certificate = $this->repository->loadDomainCertificate( $domain ); @@ -348,7 +348,7 @@ private function executeRenewal( $domain, array $alternativeNames, $force = fals if ( $parsedCertificate->getValidTo()->format( 'U' ) - time() >= 604800 ) { - EE::log( + \EE::log( sprintf( 'Current certificate is valid until %s, renewal is not necessary.', $parsedCertificate->getValidTo()->format( 'Y-m-d H:i:s' ) @@ -358,55 +358,55 @@ private function executeRenewal( $domain, array $alternativeNames, $force = fals return; } - EE::log( + \EE::log( sprintf( 'Current certificate will expire in less than a week (%s), renewal is required.', $parsedCertificate->getValidTo()->format( 'Y-m-d H:i:s' ) ) ); } else { - EE::log( 'Forced renewal.' ); + \EE::log( 'Forced renewal.' ); } // Key pair - EE::debug( 'Loading domain key pair...' ); + \EE::debug( 'Loading domain key pair...' ); $domainKeyPair = $this->repository->loadDomainKeyPair( $domain ); // Distinguished name - EE::debug( 'Loading domain distinguished name...' ); + \EE::debug( 'Loading domain distinguished name...' ); $distinguishedName = $this->getOrCreateDistinguishedName( $domain, $alternativeNames ); // Order $domains = array_merge( [ $domain ], $alternativeNames ); - EE::debug( sprintf( 'Loading the order related to the domains %s.', implode( ', ', $domains ) ) ); + \EE::debug( sprintf( 'Loading the order related to the domains %s.', implode( ', ', $domains ) ) ); if ( ! $this->repository->hasCertificateOrder( $domains ) ) { - EE::error( "$domain has not yet been authorized." ); + \EE::error( "$domain has not yet been authorized." ); } $order = $this->repository->loadCertificateOrder( $domains ); // Renewal - EE::log( sprintf( 'Renewing certificate for domain %s.', $domain ) ); + \EE::log( sprintf( 'Renewing certificate for domain %s.', $domain ) ); $csr = new CertificateRequest( $distinguishedName, $domainKeyPair ); $response = $this->client->finalizeOrder( $order, $csr ); - EE::log( 'Certificate received' ); + \EE::log( 'Certificate received' ); $this->repository->storeDomainCertificate( $domain, $response->getCertificate() ); $this->log( 'Certificate stored' ); // Post-generate actions $this->moveCertsToNginxProxy( $domain ); - EE::log( 'Certificate renewed successfully!' ); + \EE::log( 'Certificate renewed successfully!' ); } catch ( \Exception $e ) { - EE::warning( 'A critical error occured during certificate renewal' ); - EE::debug( print_r( $e, true ) ); + \EE::warning( 'A critical error occured during certificate renewal' ); + \EE::debug( print_r( $e, true ) ); throw $e; } catch ( \Throwable $e ) { - EE::warning( 'A critical error occured during certificate renewal' ); - EE::debug( print_r( $e, true ) ); + \EE::warning( 'A critical error occured during certificate renewal' ); + \EE::debug( print_r( $e, true ) ); throw $e; } @@ -524,8 +524,8 @@ public function status() { public function cleanup( $site_root ) { $challange_dir = "$site_root/app/src/.well-known"; if ( file_exists( "$site_root/app/src/.well-known" ) ) { - EE::debug( 'Cleaning up webroot files.' ); - EE\Utils\delete_dir( $challange_dir ); + \EE::debug( 'Cleaning up webroot files.' ); + \EE\Utils\delete_dir( $challange_dir ); } } } From 000c41336b60884ff71156923e29705be99e2f38 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Tue, 28 Aug 2018 23:34:06 +0530 Subject: [PATCH 45/81] Update execeptions according to namespace changes Signed-off-by: Riddhesh Sanghvi --- src/HTML.php | 8 ++++---- src/Site_Letsencrypt.php | 6 +++--- src/class-ee-site.php | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/HTML.php b/src/HTML.php index f55dc371..182192bb 100644 --- a/src/HTML.php +++ b/src/HTML.php @@ -196,7 +196,7 @@ private function configure_site_files() { $this->fs->dumpFile( $site_src_dir . '/index.html', $index_html ); \EE::success( 'Configuration files copied.' ); - } catch ( Exception $e ) { + } catch ( \Exception $e ) { $this->catch_clean( $e ); } } @@ -239,7 +239,7 @@ private function create_site() { \EE\Site\Utils\add_site_redirects( $this->site['url'], true, 'inherit' === $this->ssl ); \EE\Site\Utils\reload_proxy_configuration(); } - } catch ( Exception $e ) { + } catch ( \Exception $e ) { $this->catch_clean( $e ); } @@ -270,7 +270,7 @@ private function create_site_db_entry() { } else { throw new Exception( 'Error creating site entry in database.' ); } - } catch ( Exception $e ) { + } catch ( \Exception $e ) { $this->catch_clean( $e ); } } @@ -313,7 +313,7 @@ public function reload( $args, $assoc_args, $whitelisted_containers = [], $reloa /** * Catch and clean exceptions. * - * @param Exception $e + * @param \Exception $e */ private function catch_clean( $e ) { diff --git a/src/Site_Letsencrypt.php b/src/Site_Letsencrypt.php index 56e426d2..af0204ec 100644 --- a/src/Site_Letsencrypt.php +++ b/src/Site_Letsencrypt.php @@ -113,7 +113,7 @@ public function register( $email ) { try { $this->client->registerAccount( null, $email ); } - catch ( Exception $e ) { + catch ( \Exception $e ) { \EE::warning( $e->getMessage() ); \EE::warning( 'It seems you\'re in local environment or there is some issue with network, please check logs. Skipping letsencrypt.' ); @@ -129,7 +129,7 @@ public function authorize( Array $domains, $site_root, $wildcard = false ) { try { $order = $this->client->requestOrder( $domains ); } - catch ( Exception $e ) { + catch ( \Exception $e ) { \EE::warning( $e->getMessage() ); \EE::warning( 'It seems you\'re in local environment or using non-public domain, please check logs. Skipping letsencrypt.' ); @@ -229,7 +229,7 @@ public function check( Array $domains, $wildcard = false ) { try { $this->client->challengeAuthorization( $authorizationChallenge ); } - catch ( Exception $e ) { + catch ( \Exception $e ) { \EE::debug( $e->getMessage() ); \EE::warning( 'Challange Authorization failed. Check logs and check if your domain is pointed correctly to this server.' ); $site_name = isset( $domains[1] ) ? $domains[1] : $domains[0]; diff --git a/src/class-ee-site.php b/src/class-ee-site.php index db3ce914..8f7147aa 100644 --- a/src/class-ee-site.php +++ b/src/class-ee-site.php @@ -155,7 +155,7 @@ protected function delete_site( $level, $site_name, $site_root ) { if ( $this->fs->exists( $site_root ) ) { try { $this->fs->remove( $site_root ); - } catch ( Exception $e ) { + } catch ( \Exception $e ) { \EE::debug( $e ); \EE::error( 'Could not remove site root. Please check if you have sufficient rights.' ); } @@ -167,7 +167,7 @@ protected function delete_site( $level, $site_name, $site_root ) { if ( $this->fs->exists( $config_file_path ) ) { try { $this->fs->remove( $config_file_path ); - } catch ( Exception $e ) { + } catch ( \Exception $e ) { \EE::debug( $e ); \EE::error( 'Could not remove site redirection file. Please check if you have sufficient rights.' ); } @@ -185,7 +185,7 @@ protected function delete_site( $level, $site_name, $site_root ) { $cert_files = [$conf_certs, $conf_var, $crt_file, $key_file]; try { $this->fs->remove( $cert_files ); - } catch ( Exception $e ) { + } catch ( \Exception $e ) { \EE::warning( $e ); } } From 4426cb451565cb080cd6f6cc3deaaccc2e041a80 Mon Sep 17 00:00:00 2001 From: Mriyam Tamuli Date: Wed, 29 Aug 2018 11:23:47 +0530 Subject: [PATCH 46/81] Add spaces to .travis.yml to fix syntax Signed-off-by: Mriyam Tamuli --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 918eb470..f8c66ad2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,8 +8,8 @@ env: - TEST_COMMAND=$(echo $TRAVIS_REPO_SLUG | cut -d/ -f 2) # Get command name to be tested before_script: - - sudo curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose - - | + - sudo curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose + - | # Remove Xdebug for a huge performance increase: if [ -f ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini ]; then phpenv config-rm xdebug.ini From c9590a57c9d222a86eef985713dc4d99c8938d8c Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Wed, 29 Aug 2018 12:04:24 +0530 Subject: [PATCH 47/81] Move hooks to helper Signed-off-by: Riddhesh Sanghvi --- site-command.php | 35 ++++------------------------------- src/helper/hooks.php | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 31 deletions(-) create mode 100644 src/helper/hooks.php diff --git a/site-command.php b/site-command.php index a672fcf8..54ec7df3 100644 --- a/site-command.php +++ b/site-command.php @@ -15,38 +15,11 @@ require_once $autoload; } -// Load utility functions -require_once 'src/site-utils.php'; +// Load utility functions. +require_once 'src/helper/site-utils.php'; -function Before_Help_Command( $args, $assoc_args ) { - - if ( isset( $args[0] ) && 'site' === $args[0] ) { - $site_types = Site_Command::get_site_types(); - if ( isset( $assoc_args['type'] ) ) { - $type = $assoc_args['type']; - } else { - //TODO: get from config. - $type = 'html'; - } - - if ( isset( $site_types[ $type ] ) ) { - $callback = $site_types[ $type ]; - - $command = EE::get_root_command(); - $leaf_command = CommandFactory::create( 'site', $callback, $command ); - $command->add_subcommand( 'site', $leaf_command ); - } else { - $error = sprintf( - "'%s' is not a registered site type of 'ee site --type=%s'. See 'ee help site --type=%s' for available subcommands.", - $type, - $type, - $type - ); - EE::error( $error ); - } - } -} +// Load hooks. +require_once 'src/helper/hooks.php'; EE::add_command( 'site', 'Site_Command' ); -EE::add_hook( 'before_invoke:help', 'Before_Help_Command' ); Site_Command::add_site_type( 'html', 'EE\Site\Type\HTML' ); diff --git a/src/helper/hooks.php b/src/helper/hooks.php new file mode 100644 index 00000000..d0254f96 --- /dev/null +++ b/src/helper/hooks.php @@ -0,0 +1,35 @@ +add_subcommand( 'site', $leaf_command ); + } else { + $error = sprintf( + "'%s' is not a registered site type of 'ee site --type=%s'. See 'ee help site --type=%s' for available subcommands.", + $type, + $type, + $type + ); + EE::error( $error ); + } + } +} + +EE::add_hook( 'before_invoke:help', 'Before_Help_Command' ); From f5d6ccee795ded81f7c2abfd381934d92ef97d8a Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Wed, 29 Aug 2018 12:05:15 +0530 Subject: [PATCH 48/81] Reorganize files to helper and site-type folders Signed-off-by: Riddhesh Sanghvi --- src/{ => helper}/Shutdown_Handler.php | 3 +- src/{ => helper}/Site_Letsencrypt.php | 32 ++++++------ src/{ => helper}/class-ee-site.php | 65 +++++++++++++----------- src/{ => helper}/site-utils.php | 19 +++---- src/{ => site-type}/HTML.php | 15 +++--- src/{ => site-type}/Site_HTML_Docker.php | 1 + 6 files changed, 70 insertions(+), 65 deletions(-) rename src/{ => helper}/Shutdown_Handler.php (74%) rename src/{ => helper}/Site_Letsencrypt.php (97%) rename src/{ => helper}/class-ee-site.php (89%) rename src/{ => helper}/site-utils.php (95%) rename src/{ => site-type}/HTML.php (96%) rename src/{ => site-type}/Site_HTML_Docker.php (99%) diff --git a/src/Shutdown_Handler.php b/src/helper/Shutdown_Handler.php similarity index 74% rename from src/Shutdown_Handler.php rename to src/helper/Shutdown_Handler.php index 7a7bdebf..1d320bcd 100644 --- a/src/Shutdown_Handler.php +++ b/src/helper/Shutdown_Handler.php @@ -7,7 +7,8 @@ class Shutdown_Handler { /** - * Handle fatal errors. This function was created as the register_shutdown_function requires the callable function to be public and any public function inside site-command would be callable directly through command-line. + * Handle fatal errors. This function was created as the register_shutdown_function requires the callable function + * to be public and any public function inside site-command would be callable directly through command-line. * * @param array $site_command having Site_Command object. */ diff --git a/src/Site_Letsencrypt.php b/src/helper/Site_Letsencrypt.php similarity index 97% rename from src/Site_Letsencrypt.php rename to src/helper/Site_Letsencrypt.php index af0204ec..6fd81117 100644 --- a/src/Site_Letsencrypt.php +++ b/src/helper/Site_Letsencrypt.php @@ -1,6 +1,7 @@ client->registerAccount( null, $email ); - } - catch ( \Exception $e ) { + } catch ( \Exception $e ) { \EE::warning( $e->getMessage() ); \EE::warning( 'It seems you\'re in local environment or there is some issue with network, please check logs. Skipping letsencrypt.' ); return false; } \EE::debug( "Account with email id: $email registered successfully!" ); + return true; } @@ -128,8 +129,7 @@ public function authorize( Array $domains, $site_root, $wildcard = false ) { $solverName = $wildcard ? 'dns-01' : 'http-01'; try { $order = $this->client->requestOrder( $domains ); - } - catch ( \Exception $e ) { + } catch ( \Exception $e ) { \EE::warning( $e->getMessage() ); \EE::warning( 'It seems you\'re in local environment or using non-public domain, please check logs. Skipping letsencrypt.' ); @@ -178,7 +178,7 @@ public function authorize( Array $domains, $site_root, $wildcard = false ) { } public function check( Array $domains, $wildcard = false ) { - \EE::debug( ('Starting check with solver ') . ($wildcard ? 'dns' : 'http') ); + \EE::debug( ( 'Starting check with solver ' ) . ( $wildcard ? 'dns' : 'http' ) ); $solver = $wildcard ? new SimpleDnsSolver( null, new ConsoleOutput() ) : new SimpleHttpSolver(); $validator = new ChainValidator( [ @@ -228,8 +228,7 @@ public function check( Array $domains, $wildcard = false ) { \EE::debug( sprintf( 'Requesting authorization check for domain %s', $domain ) ); try { $this->client->challengeAuthorization( $authorizationChallenge ); - } - catch ( \Exception $e ) { + } catch ( \Exception $e ) { \EE::debug( $e->getMessage() ); \EE::warning( 'Challange Authorization failed. Check logs and check if your domain is pointed correctly to this server.' ); $site_name = isset( $domains[1] ) ? $domains[1] : $domains[0]; @@ -251,10 +250,11 @@ public function check( Array $domains, $wildcard = false ) { $solver->cleanup( $authorizationChallenge ); } } + return true; } - public function request( $domain, $altNames = [], $email, $force=false ) { + public function request( $domain, $altNames = [], $email, $force = false ) { $alternativeNames = array_unique( $altNames ); sort( $alternativeNames ); @@ -275,7 +275,7 @@ public function request( $domain, $altNames = [], $email, $force=false ) { * Request a first certificate for the given domain. * * @param string $domain - * @param array $alternativeNames + * @param array $alternativeNames */ private function executeFirstRequest( $domain, array $alternativeNames, $email ) { \EE::log( 'Executing first request.' ); @@ -332,8 +332,8 @@ private function moveCertsToNginxProxy( string $domain ) { * Renew a given domain certificate. * * @param string $domain - * @param array $alternativeNames - * @param bool $force + * @param array $alternativeNames + * @param bool $force */ private function executeRenewal( $domain, array $alternativeNames, $force = false ) { try { @@ -397,14 +397,12 @@ private function executeRenewal( $domain, array $alternativeNames, $force = fals $this->moveCertsToNginxProxy( $domain ); \EE::log( 'Certificate renewed successfully!' ); - } - catch ( \Exception $e ) { + } catch ( \Exception $e ) { \EE::warning( 'A critical error occured during certificate renewal' ); \EE::debug( print_r( $e, true ) ); throw $e; - } - catch ( \Throwable $e ) { + } catch ( \Throwable $e ) { \EE::warning( 'A critical error occured during certificate renewal' ); \EE::debug( print_r( $e, true ) ); @@ -436,7 +434,7 @@ private function hasValidCertificate( $domain, array $alternativeNames ) { * Retrieve the stored distinguishedName or create a new one if needed. * * @param string $domain - * @param array $alternativeNames + * @param array $alternativeNames * * @return DistinguishedName */ @@ -521,7 +519,7 @@ public function status() { $table->render(); } - public function cleanup( $site_root ) { + public function cleanup( $site_root ) { $challange_dir = "$site_root/app/src/.well-known"; if ( file_exists( "$site_root/app/src/.well-known" ) ) { \EE::debug( 'Cleaning up webroot files.' ); diff --git a/src/class-ee-site.php b/src/helper/class-ee-site.php similarity index 89% rename from src/class-ee-site.php rename to src/helper/class-ee-site.php index 8f7147aa..4166c791 100644 --- a/src/class-ee-site.php +++ b/src/helper/class-ee-site.php @@ -1,6 +1,7 @@ site = $site->site_url; + $site->site = $site->site_url; $site->status = $site->site_enabled ? 'enabled' : 'disabled'; return $site; @@ -128,7 +129,7 @@ public function delete( $args, $assoc_args ) { /** * Function to delete the given site. * - * @param int $level Level of deletion. + * @param int $level Level of deletion. * Level - 0: No need of clean-up. * Level - 1: Clean-up only the site-root. * Level - 2: Try to remove network. The network may or may not have been created. @@ -139,7 +140,7 @@ public function delete( $args, $assoc_args ) { */ protected function delete_site( $level, $site_name, $site_root ) { - $this->fs = new Filesystem(); + $this->fs = new Filesystem(); $proxy_type = EE_PROXY_TYPE; if ( $level >= 3 ) { if ( \EE::docker()::docker_compose_down( $site_root ) ) { @@ -177,12 +178,12 @@ protected function delete_site( $level, $site_name, $site_root ) { if ( $level > 4 ) { if ( $this->ssl ) { \EE::log( 'Removing ssl certs.' ); - $crt_file = EE_CONF_ROOT . "/nginx/certs/$site_name.crt"; - $key_file = EE_CONF_ROOT . "/nginx/certs/$site_name.key"; + $crt_file = EE_CONF_ROOT . "/nginx/certs/$site_name.crt"; + $key_file = EE_CONF_ROOT . "/nginx/certs/$site_name.key"; $conf_certs = EE_CONF_ROOT . "/acme-conf/certs/$site_name"; - $conf_var = EE_CONF_ROOT . "/acme-conf/var/$site_name"; + $conf_var = EE_CONF_ROOT . "/acme-conf/var/$site_name"; - $cert_files = [$conf_certs, $conf_var, $crt_file, $key_file]; + $cert_files = [ $conf_certs, $conf_var, $crt_file, $key_file ]; try { $this->fs->remove( $cert_files ); } catch ( \Exception $e ) { @@ -214,9 +215,9 @@ public function up( $args, $assoc_args ) { \EE\Utils\delem_log( 'site enable start' ); $force = \EE\Utils\get_flag_value( $assoc_args, 'force' ); - $args = EE\SiteUtils\auto_site_name( $args, 'site', __FUNCTION__ ); + $args = EE\SiteUtils\auto_site_name( $args, 'site', __FUNCTION__ ); $this->populate_site_info( $args ); - $site = Site::find( $this->site['url'] ); + $site = Site::find( $this->site['url'] ); if ( $site->site_enabled && ! $force ) { \EE::error( sprintf( '%s is already enabled!', $site->site_url ) ); @@ -248,7 +249,7 @@ public function down( $args, $assoc_args ) { $args = EE\SiteUtils\auto_site_name( $args, 'site', __FUNCTION__ ); $this->populate_site_info( $args ); - $site = Site::find($this->site['url']); + $site = Site::find( $this->site['url'] ); \EE::log( sprintf( 'Disabling site %s.', $site->site_url ) ); @@ -279,8 +280,8 @@ public function down( $args, $assoc_args ) { public function restart( $args, $assoc_args, $whitelisted_containers = [] ) { \EE\Utils\delem_log( 'site restart start' ); - $args = EE\SiteUtils\auto_site_name( $args, 'site', __FUNCTION__ ); - $all = \EE\Utils\get_flag_value( $assoc_args, 'all' ); + $args = EE\SiteUtils\auto_site_name( $args, 'site', __FUNCTION__ ); + $all = \EE\Utils\get_flag_value( $assoc_args, 'all' ); $no_service_specified = count( $assoc_args ) === 0; $this->populate_site_info( $args ); @@ -317,8 +318,8 @@ public function reload( $args, $assoc_args, $whitelisted_containers = [], $reloa \EE\Utils\delem_log( 'site reload start' ); $args = EE\SiteUtils\auto_site_name( $args, 'site', __FUNCTION__ ); - $all = \EE\Utils\get_flag_value( $assoc_args, 'all' ); - if ( !array_key_exists( 'nginx', $reload_commands ) ) { + $all = \EE\Utils\get_flag_value( $assoc_args, 'all' ); + if ( ! array_key_exists( 'nginx', $reload_commands ) ) { $reload_commands['nginx'] = 'nginx sh -c \'nginx -t && service openresty reload\''; } $no_service_specified = count( $assoc_args ) === 0; @@ -344,14 +345,14 @@ public function reload( $args, $assoc_args, $whitelisted_containers = [], $reloa private function reload_services( $services, $reload_commands ) { foreach ( $services as $service ) { - EE\SiteUtils\run_compose_command( 'exec', $reload_commands[$service], 'reload', $service ); + EE\SiteUtils\run_compose_command( 'exec', $reload_commands[ $service ], 'reload', $service ); } } /** * Runs the acme le registration and authorization. * - * @param string $site_name Name of the site for ssl. + * @param string $site_name Name of the site for ssl. * * @throws Exception */ @@ -381,7 +382,7 @@ protected function inherit_certs( $site_name ) { * @param string $site_name Name of the site for ssl. * @param string $site_root Webroot of the site. * @param string $ssl_type Type of ssl cert to issue. - * @param bool $wildcard SSL with wildcard or not. + * @param bool $wildcard SSL with wildcard or not. * * @throws \EE\ExitException If --ssl flag has unrecognized value */ @@ -406,16 +407,16 @@ protected function init_ssl( $site_name, $site_root, $ssl_type, $wildcard = fals * * @param string $site_name Name of the site for ssl. * @param string $site_root Webroot of the site. - * @param bool $wildcard SSL with wildcard or not. + * @param bool $wildcard SSL with wildcard or not. */ protected function init_le( $site_name, $site_root, $wildcard = false ) { \EE::debug( "Wildcard in init_le: $wildcard" ); - $this->site['url'] = $site_name; + $this->site['url'] = $site_name; $this->site['root'] = $site_root; - $this->wildcard = $wildcard; - $client = new Site_Letsencrypt(); - $this->le_mail = \EE::get_runner()->config['le-mail'] ?? \EE::input( 'Enter your mail id: ' ); + $this->wildcard = $wildcard; + $client = new Site_Letsencrypt(); + $this->le_mail = \EE::get_runner()->config['le-mail'] ?? \EE::input( 'Enter your mail id: ' ); \EE::get_runner()->ensure_present_in_config( 'le-mail', $this->le_mail ); if ( ! $client->register( $this->le_mail ) ) { $this->ssl = null; @@ -441,11 +442,11 @@ protected function init_le( $site_name, $site_root, $wildcard = false ) { * Returns all domains required by cert * * @param string $site_name Name of site - * @param $wildcard Wildcard cert required? + * @param $wildcard Wildcard cert required? * * @return array */ - private function get_cert_domains( string $site_name, $wildcard ) : array { + private function get_cert_domains( string $site_name, $wildcard ): array { $domains = [ $site_name ]; $has_www = ( strpos( $site_name, 'www.' ) === 0 ); @@ -454,6 +455,7 @@ private function get_cert_domains( string $site_name, $wildcard ) : array { } else { $domains[] = $this->get_www_domain( $site_name ); } + return $domains; } @@ -465,13 +467,13 @@ private function get_cert_domains( string $site_name, $wildcard ) : array { * * @return string Domain name with or without www */ - private function get_www_domain( string $site_name ) : string { + private function get_www_domain( string $site_name ): string { $has_www = ( strpos( $site_name, 'www.' ) === 0 ); if ( $has_www ) { return ltrim( $site_name, 'www.' ); } else { - return 'www.' . $site_name; + return 'www.' . $site_name; } } @@ -489,11 +491,11 @@ private function get_www_domain( string $site_name ) : string { */ public function le( $args = [], $assoc_args = [] ) { - if ( !isset( $this->site['url'] ) ) { + if ( ! isset( $this->site['url'] ) ) { $this->populate_site_info( $args ); } - if ( !isset( $this->le_mail ) ) { + if ( ! isset( $this->le_mail ) ) { $this->le_mail = \EE::get_config( 'le-mail' ) ?? \EE::input( 'Enter your mail id: ' ); } @@ -503,6 +505,7 @@ public function le( $args = [], $assoc_args = [] ) { if ( ! $client->check( $domains, $this->wildcard ) ) { $this->ssl = null; + return; } @@ -521,7 +524,7 @@ public function le( $args = [], $assoc_args = [] ) { private function populate_site_info( $args ) { $this->site['url'] = \EE\Utils\remove_trailing_slash( $args[0] ); - $site = Site::find( $this->site['url'] ); + $site = Site::find( $this->site['url'] ); if ( $site ) { $db_select = $site->site_url; diff --git a/src/site-utils.php b/src/helper/site-utils.php similarity index 95% rename from src/site-utils.php rename to src/helper/site-utils.php index e912cb02..0092c19b 100644 --- a/src/site-utils.php +++ b/src/helper/site-utils.php @@ -15,7 +15,7 @@ function get_site_name() { $sites = Site::all( [ 'site_url' ] ); if ( ! empty( $sites ) ) { - $cwd = getcwd(); + $cwd = getcwd(); $name_in_path = explode( '/', $cwd ); $site_name = array_intersect( array_column( $sites, 'site_url' ), $name_in_path ); @@ -50,10 +50,10 @@ function auto_site_name( $args, $command, $function, $arg_pos = 0 ) { if ( isset( $args[ $arg_pos ] ) ) { $possible_site_name = $args[ $arg_pos ]; - if( substr( $possible_site_name, 0, 4 ) === 'http' ) { - $possible_site_name = str_replace(['https','http'],'',$possible_site_name); + if ( substr( $possible_site_name, 0, 4 ) === 'http' ) { + $possible_site_name = str_replace( [ 'https', 'http' ], '', $possible_site_name ); } - $url_path = parse_url(EE\Utils\remove_trailing_slash($possible_site_name), PHP_URL_PATH); + $url_path = parse_url( EE\Utils\remove_trailing_slash( $possible_site_name ), PHP_URL_PATH ); if ( Site::find( $url_path ) ) { return $args; } @@ -122,7 +122,7 @@ function init_checks() { function generate_global_docker_compose_yml( Filesystem $fs ) { $img_versions = EE\Utils\get_image_versions(); - $data = [ + $data = [ 'services' => [ 'name' => 'nginx-proxy', 'container_name' => EE_PROXY_TYPE, @@ -189,8 +189,8 @@ function reload_proxy_configuration() { * Adds www to non-www redirection to site * * @param string $site_name name of the site. - * @param bool $ssl enable ssl or not. - * @param bool $inherit inherit cert or not. + * @param bool $ssl enable ssl or not. + * @param bool $inherit inherit cert or not. */ function add_site_redirects( string $site_name, bool $ssl, bool $inherit ) { @@ -297,8 +297,9 @@ function get_curl_info( $url, $port = 80, $port_info = false ) { /** * Function to pull the latest images and bring up the site containers. * - * @param string $site_root Root directory of the site. - * @param array $containers The minimum required conatainers to start the site. Default null, leads to starting of all containers. + * @param string $site_root Root directory of the site. + * @param array $containers The minimum required conatainers to start the site. Default null, leads to starting of all + * containers. * * @throws \Exception when docker-compose up fails. */ diff --git a/src/HTML.php b/src/site-type/HTML.php similarity index 96% rename from src/HTML.php rename to src/site-type/HTML.php index 182192bb..57d0438d 100644 --- a/src/HTML.php +++ b/src/site-type/HTML.php @@ -14,6 +14,7 @@ */ namespace EE\Site\Type; + use \EE\Model\Site; use \Symfony\Component\Filesystem\Filesystem; @@ -62,7 +63,7 @@ class HTML extends EE_Site_Command { public function __construct() { - $this->level = 0; + $this->level = 0; pcntl_signal( SIGTERM, [ $this, "rollback" ] ); pcntl_signal( SIGHUP, [ $this, "rollback" ] ); pcntl_signal( SIGUSR1, [ $this, "rollback" ] ); @@ -99,7 +100,7 @@ public function create( $args, $assoc_args ) { \EE::warning( 'This is a beta version. Please don\'t use it in production.' ); $this->logger->debug( 'args:', $args ); $this->logger->debug( 'assoc_args:', empty( $assoc_args ) ? [ 'NULL' ] : $assoc_args ); - $this->site['url'] = strtolower( \EE\Utils\remove_trailing_slash( $args[0] ) ); + $this->site['url'] = strtolower( \EE\Utils\remove_trailing_slash( $args[0] ) ); $this->site['type'] = \EE\Utils\get_flag_value( $assoc_args, 'type', 'html' ); if ( 'html' !== $this->site['type'] ) { \EE::error( sprintf( 'Invalid site-type: %s', $this->site['type'] ) ); @@ -111,7 +112,7 @@ public function create( $args, $assoc_args ) { $this->ssl = \EE\Utils\get_flag_value( $assoc_args, 'ssl' ); $this->ssl_wildcard = \EE\Utils\get_flag_value( $assoc_args, 'wildcard' ); - $this->skip_chk = \EE\Utils\get_flag_value( $assoc_args, 'skip-status-check' ); + $this->skip_chk = \EE\Utils\get_flag_value( $assoc_args, 'skip-status-check' ); \EE\Site\Utils\init_checks(); @@ -143,7 +144,7 @@ public function info( $args, $assoc_args ) { ]; if ( $this->ssl ) { - $info[] = [ 'SSL Wildcard', $this->ssl_wildcard ? 'Yes': 'No' ]; + $info[] = [ 'SSL Wildcard', $this->ssl_wildcard ? 'Yes' : 'No' ]; } \EE\Utils\format_table( $info ); @@ -252,17 +253,17 @@ private function create_site() { */ private function create_site_db_entry() { - $ssl = $this->ssl ? 1 : 0; + $ssl = $this->ssl ? 1 : 0; $ssl_wildcard = $this->ssl_wildcard ? 1 : 0; - $site = Site::create([ + $site = Site::create( [ 'site_url' => $this->site['url'], 'site_type' => $this->site['type'], 'site_fs_path' => $this->site['root'], 'site_ssl' => $ssl, 'site_ssl_wildcard' => $ssl_wildcard, 'created_on' => date( 'Y-m-d H:i:s', time() ), - ]); + ] ); try { if ( $site ) { diff --git a/src/Site_HTML_Docker.php b/src/site-type/Site_HTML_Docker.php similarity index 99% rename from src/Site_HTML_Docker.php rename to src/site-type/Site_HTML_Docker.php index 8ce8dfc2..8f4e5b39 100644 --- a/src/Site_HTML_Docker.php +++ b/src/site-type/Site_HTML_Docker.php @@ -1,6 +1,7 @@ Date: Wed, 29 Aug 2018 14:06:55 +0530 Subject: [PATCH 49/81] Move use statement to hooks file Signed-off-by: Riddhesh Sanghvi --- site-command.php | 2 -- src/helper/hooks.php | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/site-command.php b/site-command.php index 54ec7df3..cc57adac 100644 --- a/site-command.php +++ b/site-command.php @@ -1,7 +1,5 @@ Date: Wed, 29 Aug 2018 14:07:38 +0530 Subject: [PATCH 50/81] Update doc comment Signed-off-by: Riddhesh Sanghvi --- src/site-type/HTML.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/site-type/HTML.php b/src/site-type/HTML.php index 57d0438d..590e8217 100644 --- a/src/site-type/HTML.php +++ b/src/site-type/HTML.php @@ -76,7 +76,7 @@ public function __construct() { } /** - * Runs the standard WordPress site installation. + * Runs the standard HTML site installation. * * ## OPTIONS * @@ -89,7 +89,7 @@ public function __construct() { * [--wildcard] * : Gets wildcard SSL . * [--type=] - * : Type of the site to be created. Values: html,php,wp. + * : Type of the site to be created. Values: html,php,wp etc. * * [--skip-status-check] * : Skips site status check. From ed5c6e094d2b7643f406632130846c0154b03ac4 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Wed, 29 Aug 2018 16:19:41 +0530 Subject: [PATCH 51/81] Update warning message Signed-off-by: Riddhesh Sanghvi --- src/Site_Command.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Site_Command.php b/src/Site_Command.php index 636454d6..eaf906b8 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -38,7 +38,7 @@ public static function instance() { public static function add_site_type( $name, $callback ) { if ( isset( self::$instance->site_types[ $name ] ) ) { - EE::warning( sprintf( '%s site-type has already been previously registered by %s. It will be over-written by the new package class %s. Please update your packages to resolve this.', $name, self::$instance->site_types[ $name ], $callback ) ); + EE::warning( sprintf( '%s site-type had already been previously registered by %s. It is overridden by the new package class %s. Please update your packages to resolve this.', $name, self::$instance->site_types[ $name ], $callback ) ); } self::$instance->site_types[ $name ] = $callback; } From eb2e1e42196da1345e022e7bc0efe11b38814512 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Wed, 29 Aug 2018 16:21:42 +0530 Subject: [PATCH 52/81] Update sprintf Signed-off-by: Riddhesh Sanghvi --- src/Site_Command.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Site_Command.php b/src/Site_Command.php index eaf906b8..12bf25d1 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -73,9 +73,7 @@ public function __invoke( $args, $assoc_args ) { if ( ! isset( $site_types[ $type ] ) ) { $error = sprintf( - "'%s' is not a registered site type of 'ee site --type=%s'. See 'ee help site --type=%s' for available subcommands.", - $type, - $type, + '\'%1$s\' is not a registered site type of \'ee site --type=%1$s\'. See \'ee help site --type=%1$s\' for available subcommands.', $type ); EE::error( $error ); From 69b69764b36272ecbeb8e33bd2e149135bffff56 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Wed, 29 Aug 2018 16:29:09 +0530 Subject: [PATCH 53/81] Remove TODO from code to track in seperate issue Signed-off-by: Riddhesh Sanghvi --- src/Site_Command.php | 4 ---- src/helper/hooks.php | 1 - 2 files changed, 5 deletions(-) diff --git a/src/Site_Command.php b/src/Site_Command.php index 12bf25d1..a6495a67 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -104,10 +104,6 @@ private function determine_type( $args ) { // default site-type $type = 'html'; - // TODO: get type from config file as below - // $config_type = EE::get_config('type'); - // $type = empty( $config_type ) ? 'html' : $config_type; - $last_arg = array_pop( $args ); if ( substr( $last_arg, 0, 4 ) === 'http' ) { $last_arg = str_replace( [ 'https://', 'http://' ], '', $last_arg ); diff --git a/src/helper/hooks.php b/src/helper/hooks.php index 16af8399..37609c1b 100644 --- a/src/helper/hooks.php +++ b/src/helper/hooks.php @@ -12,7 +12,6 @@ function Before_Help_Command( $args, $assoc_args ) { if ( isset( $assoc_args['type'] ) ) { $type = $assoc_args['type']; } else { - //TODO: get from config. $type = 'html'; } From 4d9dc92219bceddae042d763dda62047b84572ac Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Wed, 29 Aug 2018 16:31:39 +0530 Subject: [PATCH 54/81] Update hook name and doc comment Signed-off-by: Riddhesh Sanghvi --- src/helper/hooks.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/helper/hooks.php b/src/helper/hooks.php index 37609c1b..8e67645d 100644 --- a/src/helper/hooks.php +++ b/src/helper/hooks.php @@ -3,9 +3,12 @@ use EE\Dispatcher\CommandFactory; /** - * Add hook before the invocation of help command to appropriately handle the help for given site-type. + * Callback function of `before_invoke:help` hook: Add routing for "ee help site" command before the invocation of help command. + * + * @param array $args Commandline arguments passed to help command. + * @param array $assoc_args Associative arguments passed to help command. */ -function Before_Help_Command( $args, $assoc_args ) { +function ee_site_help_cmd_routing( $args, $assoc_args ) { if ( isset( $args[0] ) && 'site' === $args[0] ) { $site_types = Site_Command::get_site_types(); @@ -33,4 +36,4 @@ function Before_Help_Command( $args, $assoc_args ) { } } -EE::add_hook( 'before_invoke:help', 'Before_Help_Command' ); +EE::add_hook( 'before_invoke:help', 'ee_site_help_cmd_routing' ); From 4f66fc202a227d2e7d63ecb660669f55ba53e269 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Wed, 29 Aug 2018 16:35:53 +0530 Subject: [PATCH 55/81] Add early return in help hook Signed-off-by: Riddhesh Sanghvi --- src/helper/hooks.php | 52 ++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/src/helper/hooks.php b/src/helper/hooks.php index 8e67645d..043778ff 100644 --- a/src/helper/hooks.php +++ b/src/helper/hooks.php @@ -3,37 +3,41 @@ use EE\Dispatcher\CommandFactory; /** - * Callback function of `before_invoke:help` hook: Add routing for "ee help site" command before the invocation of help command. + * Callback function of `before_invoke:help` hook: Add routing for "ee help site" command before the invocation of help + * command. * * @param array $args Commandline arguments passed to help command. * @param array $assoc_args Associative arguments passed to help command. */ function ee_site_help_cmd_routing( $args, $assoc_args ) { - if ( isset( $args[0] ) && 'site' === $args[0] ) { - $site_types = Site_Command::get_site_types(); - if ( isset( $assoc_args['type'] ) ) { - $type = $assoc_args['type']; - } else { - $type = 'html'; - } - - if ( isset( $site_types[ $type ] ) ) { - $callback = $site_types[ $type ]; - - $command = EE::get_root_command(); - $leaf_command = CommandFactory::create( 'site', $callback, $command ); - $command->add_subcommand( 'site', $leaf_command ); - } else { - $error = sprintf( - "'%s' is not a registered site type of 'ee site --type=%s'. See 'ee help site --type=%s' for available subcommands.", - $type, - $type, - $type - ); - EE::error( $error ); - } + if ( ( ! isset( $args[0] ) ) || ( 'site' !== $args[0] ) ) { + return; } + + $site_types = Site_Command::get_site_types(); + if ( isset( $assoc_args['type'] ) ) { + $type = $assoc_args['type']; + } else { + $type = 'html'; + } + + if ( isset( $site_types[ $type ] ) ) { + $callback = $site_types[ $type ]; + + $command = EE::get_root_command(); + $leaf_command = CommandFactory::create( 'site', $callback, $command ); + $command->add_subcommand( 'site', $leaf_command ); + } else { + $error = sprintf( + "'%s' is not a registered site type of 'ee site --type=%s'. See 'ee help site --type=%s' for available subcommands.", + $type, + $type, + $type + ); + EE::error( $error ); + } + } EE::add_hook( 'before_invoke:help', 'ee_site_help_cmd_routing' ); From 75e55f7f3754ba3b9e010f0a39383312095d900a Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Wed, 29 Aug 2018 16:37:51 +0530 Subject: [PATCH 56/81] Rename html class file Signed-off-by: Riddhesh Sanghvi --- src/site-type/{HTML.php => html.php} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/site-type/{HTML.php => html.php} (100%) diff --git a/src/site-type/HTML.php b/src/site-type/html.php similarity index 100% rename from src/site-type/HTML.php rename to src/site-type/html.php From 6dd18f838b470aa5bb46bc5beddb87760279dde0 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Wed, 29 Aug 2018 16:46:24 +0530 Subject: [PATCH 57/81] Update help info in doc block Signed-off-by: Riddhesh Sanghvi --- src/Site_Command.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Site_Command.php b/src/Site_Command.php index a6495a67..fbd95a9b 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -53,6 +53,7 @@ public static function get_site_types() { } /** + * Performs site operations. Check `ee help site` for more info. * Invoked function of site-type routing. Called when `ee site` is invoked. * Performs the routing to respective site-type passed using either `--type=`, * Or discovers the type from the site-name and fetches the type from it, From 18c462fe5fac0ef803f2c5486abfade4dd29b90d Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Wed, 29 Aug 2018 17:03:51 +0530 Subject: [PATCH 58/81] Update path for require Signed-off-by: Riddhesh Sanghvi --- site-command.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site-command.php b/site-command.php index cc57adac..4fcd4336 100644 --- a/site-command.php +++ b/site-command.php @@ -14,10 +14,10 @@ } // Load utility functions. -require_once 'src/helper/site-utils.php'; +require_once __DIR__ . 'src/helper/site-utils.php'; // Load hooks. -require_once 'src/helper/hooks.php'; +require_once __DIR__ . 'src/helper/hooks.php'; EE::add_command( 'site', 'Site_Command' ); Site_Command::add_site_type( 'html', 'EE\Site\Type\HTML' ); From 077316c1afcfee793d07524fcb9c313075dfeb61 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Wed, 29 Aug 2018 17:31:19 +0530 Subject: [PATCH 59/81] Move shutdownfunction and common rollback to abstract class Signed-off-by: Riddhesh Sanghvi --- src/helper/class-ee-site.php | 26 ++++++++++++++++++++++++++ src/site-type/html.php | 30 +++++------------------------- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/src/helper/class-ee-site.php b/src/helper/class-ee-site.php index 4166c791..c55c0005 100644 --- a/src/helper/class-ee-site.php +++ b/src/helper/class-ee-site.php @@ -37,6 +37,13 @@ abstract class EE_Site_Command { private $site; public function __construct() { + + pcntl_signal( SIGTERM, [ $this, "rollback" ] ); + pcntl_signal( SIGHUP, [ $this, "rollback" ] ); + pcntl_signal( SIGUSR1, [ $this, "rollback" ] ); + pcntl_signal( SIGINT, [ $this, "rollback" ] ); + $shutdown_handler = new Shutdown_Handler(); + register_shutdown_function( [ $shutdown_handler, "cleanup" ], [ &$this ] ); } /** @@ -538,6 +545,25 @@ private function populate_site_info( $args ) { } } + /** + * Shutdown function to catch and rollback from fatal errors. + */ + protected function shutDownFunction() { + + $logger = \EE::get_file_logger()->withName( 'site-command' ); + $error = error_get_last(); + if ( isset( $error ) && $error['type'] === E_ERROR ) { + \EE::warning( 'An Error occurred. Initiating clean-up.' ); + $logger->error( 'Type: ' . $error['type'] ); + $logger->error( 'Message: ' . $error['message'] ); + $logger->error( 'File: ' . $error['file'] ); + $logger->error( 'Line: ' . $error['line'] ); + $this->rollback(); + } + } + abstract public function create( $args, $assoc_args ); + abstract protected function rollback(); + } diff --git a/src/site-type/html.php b/src/site-type/html.php index 590e8217..396c1c0b 100644 --- a/src/site-type/html.php +++ b/src/site-type/html.php @@ -63,15 +63,10 @@ class HTML extends EE_Site_Command { public function __construct() { - $this->level = 0; - pcntl_signal( SIGTERM, [ $this, "rollback" ] ); - pcntl_signal( SIGHUP, [ $this, "rollback" ] ); - pcntl_signal( SIGUSR1, [ $this, "rollback" ] ); - pcntl_signal( SIGINT, [ $this, "rollback" ] ); - $shutdown_handler = new Shutdown_Handler(); - register_shutdown_function( [ $shutdown_handler, "cleanup" ], [ &$this ] ); + parent::__construct(); + $this->level = 0; $this->docker = \EE::docker(); - $this->logger = \EE::get_file_logger()->withName( 'site_command' ); + $this->logger = \EE::get_file_logger()->withName( 'html_type' ); $this->fs = new Filesystem(); } @@ -95,7 +90,7 @@ public function __construct() { * : Skips site status check. */ public function create( $args, $assoc_args ) { - + trigger_error("Cannot divide by zero", E_USER_ERROR); \EE\Utils\delem_log( 'site create start' ); \EE::warning( 'This is a beta version. Please don\'t use it in production.' ); $this->logger->debug( 'args:', $args ); @@ -329,7 +324,7 @@ private function catch_clean( $e ) { /** * Roll back on interrupt. */ - private function rollback() { + protected function rollback() { \EE::warning( 'Exiting gracefully after rolling back. This may take some time.' ); if ( $this->level > 0 ) { @@ -339,19 +334,4 @@ private function rollback() { exit; } - /** - * Shutdown function to catch and rollback from fatal errors. - */ - private function shutDownFunction() { - - $error = error_get_last(); - if ( isset( $error ) && $error['type'] === E_ERROR ) { - \EE::warning( 'An Error occurred. Initiating clean-up.' ); - $this->logger->error( 'Type: ' . $error['type'] ); - $this->logger->error( 'Message: ' . $error['message'] ); - $this->logger->error( 'File: ' . $error['file'] ); - $this->logger->error( 'Line: ' . $error['line'] ); - $this->rollback(); - } - } } From b5c167d85543141931c2841259f5fdd322fd5648 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Wed, 29 Aug 2018 17:33:22 +0530 Subject: [PATCH 60/81] Move file loading to composer Signed-off-by: Riddhesh Sanghvi --- composer.json | 6 +++++- site-command.php | 6 ------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index 2303c5bc..90c612bd 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,11 @@ "": "src/", "AcmePhp\\Cli\\": "AcmePhp/Cli" }, - "files": [ "site-command.php" ] + "files": [ + "site-command.php", + "src/helper/site-utils.php", + "src/helper/hooks.php" + ] }, "extra": { "branch-alias": { diff --git a/site-command.php b/site-command.php index 4fcd4336..5b78c171 100644 --- a/site-command.php +++ b/site-command.php @@ -13,11 +13,5 @@ require_once $autoload; } -// Load utility functions. -require_once __DIR__ . 'src/helper/site-utils.php'; - -// Load hooks. -require_once __DIR__ . 'src/helper/hooks.php'; - EE::add_command( 'site', 'Site_Command' ); Site_Command::add_site_type( 'html', 'EE\Site\Type\HTML' ); From e408a92b1f277df1593aa41ea64814b9a4ac372a Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Wed, 29 Aug 2018 17:36:57 +0530 Subject: [PATCH 61/81] Update loading sequence Signed-off-by: Riddhesh Sanghvi --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 90c612bd..81133af2 100644 --- a/composer.json +++ b/composer.json @@ -13,9 +13,9 @@ "AcmePhp\\Cli\\": "AcmePhp/Cli" }, "files": [ - "site-command.php", + "src/helper/hooks.php", "src/helper/site-utils.php", - "src/helper/hooks.php" + "site-command.php" ] }, "extra": { From 72444d874c13c2b7516de65e55f5f88539d4adc0 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Wed, 29 Aug 2018 17:45:36 +0530 Subject: [PATCH 62/81] Change hook addition Signed-off-by: Riddhesh Sanghvi --- site-command.php | 1 + src/helper/hooks.php | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/site-command.php b/site-command.php index 5b78c171..b0127971 100644 --- a/site-command.php +++ b/site-command.php @@ -14,4 +14,5 @@ } EE::add_command( 'site', 'Site_Command' ); +EE::add_hook( 'before_invoke:help', 'ee_site_help_cmd_routing' ); Site_Command::add_site_type( 'html', 'EE\Site\Type\HTML' ); diff --git a/src/helper/hooks.php b/src/helper/hooks.php index 043778ff..f2621481 100644 --- a/src/helper/hooks.php +++ b/src/helper/hooks.php @@ -39,5 +39,3 @@ function ee_site_help_cmd_routing( $args, $assoc_args ) { } } - -EE::add_hook( 'before_invoke:help', 'ee_site_help_cmd_routing' ); From eb15ce54c1869eeb905ab1d05a8efe494d045c64 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Wed, 29 Aug 2018 18:00:20 +0530 Subject: [PATCH 63/81] Remove test trigger of error Signed-off-by: Riddhesh Sanghvi --- src/site-type/html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/site-type/html.php b/src/site-type/html.php index 396c1c0b..5c279b5a 100644 --- a/src/site-type/html.php +++ b/src/site-type/html.php @@ -90,7 +90,7 @@ public function __construct() { * : Skips site status check. */ public function create( $args, $assoc_args ) { - trigger_error("Cannot divide by zero", E_USER_ERROR); + \EE\Utils\delem_log( 'site create start' ); \EE::warning( 'This is a beta version. Please don\'t use it in production.' ); $this->logger->debug( 'args:', $args ); From a313af67a770f41139b202b882e49a090d5251c7 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Wed, 29 Aug 2018 22:41:36 +0530 Subject: [PATCH 64/81] Update hooks file to add hooks Signed-off-by: Riddhesh Sanghvi --- site-command.php | 1 - src/helper/hooks.php | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/site-command.php b/site-command.php index b0127971..5b78c171 100644 --- a/site-command.php +++ b/site-command.php @@ -14,5 +14,4 @@ } EE::add_command( 'site', 'Site_Command' ); -EE::add_hook( 'before_invoke:help', 'ee_site_help_cmd_routing' ); Site_Command::add_site_type( 'html', 'EE\Site\Type\HTML' ); diff --git a/src/helper/hooks.php b/src/helper/hooks.php index f2621481..06d339f2 100644 --- a/src/helper/hooks.php +++ b/src/helper/hooks.php @@ -1,5 +1,9 @@ Date: Thu, 30 Aug 2018 13:44:59 +0530 Subject: [PATCH 65/81] Update sprintf usage Signed-off-by: Riddhesh Sanghvi --- src/helper/hooks.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/helper/hooks.php b/src/helper/hooks.php index 06d339f2..256709bc 100644 --- a/src/helper/hooks.php +++ b/src/helper/hooks.php @@ -34,9 +34,7 @@ function ee_site_help_cmd_routing( $args, $assoc_args ) { $command->add_subcommand( 'site', $leaf_command ); } else { $error = sprintf( - "'%s' is not a registered site type of 'ee site --type=%s'. See 'ee help site --type=%s' for available subcommands.", - $type, - $type, + '\'%1$s\' is not a registered site type of \'ee site --type=%1$s\'. See \'ee help site --type=%1$s\' for available subcommands.', $type ); EE::error( $error ); From cd38bc779f2fbc094ca33b7c0421eb0e15817a5c Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Thu, 30 Aug 2018 13:46:39 +0530 Subject: [PATCH 66/81] Update function name Signed-off-by: Riddhesh Sanghvi --- src/helper/Shutdown_Handler.php | 2 +- src/helper/class-ee-site.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/helper/Shutdown_Handler.php b/src/helper/Shutdown_Handler.php index 1d320bcd..db032575 100644 --- a/src/helper/Shutdown_Handler.php +++ b/src/helper/Shutdown_Handler.php @@ -14,7 +14,7 @@ class Shutdown_Handler { */ public function cleanup( $site_command ) { $reflector = new \ReflectionObject( $site_command[0] ); - $method = $reflector->getMethod( 'shutDownFunction' ); + $method = $reflector->getMethod( 'shut_down_function' ); $method->setAccessible( true ); $method->invoke( $site_command[0] ); } diff --git a/src/helper/class-ee-site.php b/src/helper/class-ee-site.php index c55c0005..8e15961c 100644 --- a/src/helper/class-ee-site.php +++ b/src/helper/class-ee-site.php @@ -548,7 +548,7 @@ private function populate_site_info( $args ) { /** * Shutdown function to catch and rollback from fatal errors. */ - protected function shutDownFunction() { + protected function shut_down_function() { $logger = \EE::get_file_logger()->withName( 'site-command' ); $error = error_get_last(); From 9370281dc3f0a2303e8b6bf069c94acb4c0a361b Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Fri, 31 Aug 2018 17:31:43 +0530 Subject: [PATCH 67/81] Refactor db related code and calls in abstract site class Signed-off-by: Riddhesh Sanghvi --- src/helper/class-ee-site.php | 253 ++++++++++++++++------------------- 1 file changed, 118 insertions(+), 135 deletions(-) diff --git a/src/helper/class-ee-site.php b/src/helper/class-ee-site.php index 8e15961c..d99f2612 100644 --- a/src/helper/class-ee-site.php +++ b/src/helper/class-ee-site.php @@ -2,8 +2,12 @@ namespace EE\Site\Type; +use function EE\Site\Utils\reload_global_nginx; use \Symfony\Component\Filesystem\Filesystem; use \EE\Model\Site; +use function \EE\Site\Utils\auto_site_name; +use function \EE\Site\Utils\get_site_info; +use function \EE\Site\Utils\reload_global_nginx_proxy; /** * Base class for Site command @@ -32,18 +36,18 @@ abstract class EE_Site_Command { private $le_mail; /** - * @var array $site Associative array containing essential site related information. + * @var array $site_data Associative array containing essential site related information. */ - private $site; + private $site_data; public function __construct() { - pcntl_signal( SIGTERM, [ $this, "rollback" ] ); - pcntl_signal( SIGHUP, [ $this, "rollback" ] ); - pcntl_signal( SIGUSR1, [ $this, "rollback" ] ); - pcntl_signal( SIGINT, [ $this, "rollback" ] ); + pcntl_signal( SIGTERM, [ $this, 'rollback' ] ); + pcntl_signal( SIGHUP, [ $this, 'rollback' ] ); + pcntl_signal( SIGUSR1, [ $this, 'rollback' ] ); + pcntl_signal( SIGINT, [ $this, 'rollback' ] ); $shutdown_handler = new Shutdown_Handler(); - register_shutdown_function( [ $shutdown_handler, "cleanup" ], [ &$this ] ); + register_shutdown_function( [ $shutdown_handler, 'cleanup' ], [ &$this ] ); } /** @@ -127,50 +131,50 @@ function ( $site ) { public function delete( $args, $assoc_args ) { \EE\Utils\delem_log( 'site delete start' ); - $this->populate_site_info( $args ); - \EE::confirm( sprintf( 'Are you sure you want to delete %s?', $this->site['url'] ), $assoc_args ); - $this->delete_site( 5, $this->site['url'], $this->site['root'] ); + $this->site_data = get_site_info( $args, false ); + \EE::confirm( sprintf( 'Are you sure you want to delete %s?', $this->site_data['site_url'] ), $assoc_args ); + $this->delete_site( 5, $this->site_data['site_url'], $this->site_data['site_fs_path'] ); \EE\Utils\delem_log( 'site delete end' ); } /** * Function to delete the given site. * - * @param int $level Level of deletion. - * Level - 0: No need of clean-up. - * Level - 1: Clean-up only the site-root. - * Level - 2: Try to remove network. The network may or may not have been created. - * Level - 3: Disconnect & remove network and try to remove containers. The containers may - * not have been created. Level - 4: Remove containers. Level - 5: Remove db entry. - * @param string $site_name Name of the site to be deleted. - * @param string $site_root Webroot of the site. + * @param int $level Level of deletion. + * Level - 0: No need of clean-up. + * Level - 1: Clean-up only the site-root. + * Level - 2: Try to remove network. The network may or may not have been created. + * Level - 3: Disconnect & remove network and try to remove containers. The containers + * may not have been created. Level - 4: Remove containers. Level - 5: Remove db entry. + * @param string $site_url Name of the site to be deleted. + * @param string $site_fs_path Webroot of the site. */ - protected function delete_site( $level, $site_name, $site_root ) { + protected function delete_site( $level, $site_url, $site_fs_path ) { + + $this->fs = new Filesystem(); - $this->fs = new Filesystem(); - $proxy_type = EE_PROXY_TYPE; if ( $level >= 3 ) { - if ( \EE::docker()::docker_compose_down( $site_root ) ) { - \EE::log( "[$site_name] Docker Containers removed." ); + if ( \EE::docker()::docker_compose_down( $site_fs_path ) ) { + \EE::log( "[$site_url] Docker Containers removed." ); } else { - \EE::exec( "docker rm -f $(docker ps -q -f=label=created_by=EasyEngine -f=label=site_name=$site_name)" ); + \EE::exec( "docker rm -f $(docker ps -q -f=label=created_by=EasyEngine -f=label=site_name=$site_url)" ); if ( $level > 3 ) { \EE::warning( 'Error in removing docker containers.' ); } } } - if ( $this->fs->exists( $site_root ) ) { + if ( $this->fs->exists( $site_fs_path ) ) { try { - $this->fs->remove( $site_root ); + $this->fs->remove( $site_fs_path ); } catch ( \Exception $e ) { \EE::debug( $e ); \EE::error( 'Could not remove site root. Please check if you have sufficient rights.' ); } - \EE::log( "[$site_name] site root removed." ); + \EE::log( "[$site_url] site root removed." ); } - $config_file_path = EE_CONF_ROOT . '/nginx/conf.d/' . $site_name . '-redirect.conf'; + $config_file_path = EE_CONF_ROOT . '/nginx/conf.d/' . $site_url . '-redirect.conf'; if ( $this->fs->exists( $config_file_path ) ) { try { @@ -183,12 +187,12 @@ protected function delete_site( $level, $site_name, $site_root ) { if ( $level > 4 ) { - if ( $this->ssl ) { + if ( $this->site_data['site_ssl'] ) { \EE::log( 'Removing ssl certs.' ); - $crt_file = EE_CONF_ROOT . "/nginx/certs/$site_name.crt"; - $key_file = EE_CONF_ROOT . "/nginx/certs/$site_name.key"; - $conf_certs = EE_CONF_ROOT . "/acme-conf/certs/$site_name"; - $conf_var = EE_CONF_ROOT . "/acme-conf/var/$site_name"; + $crt_file = EE_CONF_ROOT . "/nginx/certs/$site_url.crt"; + $key_file = EE_CONF_ROOT . "/nginx/certs/$site_url.key"; + $conf_certs = EE_CONF_ROOT . "/acme-conf/certs/$site_url"; + $conf_var = EE_CONF_ROOT . "/acme-conf/var/$site_url"; $cert_files = [ $conf_certs, $conf_var, $crt_file, $key_file ]; try { @@ -198,13 +202,13 @@ protected function delete_site( $level, $site_name, $site_root ) { } } - if ( Site::find( $site_name )->delete() ) { + if ( Site::find( $site_url )->delete() ) { \EE::log( 'Removed database entry.' ); } else { \EE::error( 'Could not remove the database entry' ); } } - \EE::log( "Site $site_name deleted." ); + \EE::log( "Site $site_url deleted." ); } /** @@ -221,23 +225,22 @@ protected function delete_site( $level, $site_name, $site_root ) { public function up( $args, $assoc_args ) { \EE\Utils\delem_log( 'site enable start' ); - $force = \EE\Utils\get_flag_value( $assoc_args, 'force' ); - $args = EE\SiteUtils\auto_site_name( $args, 'site', __FUNCTION__ ); - $this->populate_site_info( $args ); - $site = Site::find( $this->site['url'] ); + $force = \EE\Utils\get_flag_value( $assoc_args, 'force' ); + $args = auto_site_name( $args, 'site', __FUNCTION__ ); + $this->site_data = get_site_info( $args, false, true, false ); - if ( $site->site_enabled && ! $force ) { - \EE::error( sprintf( '%s is already enabled!', $site->site_url ) ); + if ( $this->site_data->site_enabled && ! $force ) { + \EE::error( sprintf( '%s is already enabled!', $this->site_data->site_url ) ); } - \EE::log( sprintf( 'Enabling site %s.', $site->site_url ) ); + \EE::log( sprintf( 'Enabling site %s.', $this->site_data->site_url ) ); - if ( \EE::docker()::docker_compose_up( $this->site['root'] ) ) { - $site->site_enabled = 1; - $site->save(); - \EE::success( "Site $site->site_url enabled." ); + if ( \EE::docker()::docker_compose_up( $this->site_data->site_fs_path ) ) { + $this->site_data->site_enabled = 1; + $this->site_data->save(); + \EE::success( sprintf( 'Site %s enabled.', $this->site_data->site_url ) ); } else { - \EE::error( sprintf( 'There was error in enabling %s. Please check logs.', $site->site_url ) ); + \EE::error( sprintf( 'There was error in enabling %s. Please check logs.', $this->site_data->site_url ) ); } \EE\Utils\delem_log( 'site enable end' ); } @@ -253,20 +256,18 @@ public function up( $args, $assoc_args ) { public function down( $args, $assoc_args ) { \EE\Utils\delem_log( 'site disable start' ); - $args = EE\SiteUtils\auto_site_name( $args, 'site', __FUNCTION__ ); - $this->populate_site_info( $args ); - - $site = Site::find( $this->site['url'] ); + $args = auto_site_name( $args, 'site', __FUNCTION__ ); + $this->site_data = get_site_info( $args, false, true, false ); - \EE::log( sprintf( 'Disabling site %s.', $site->site_url ) ); + \EE::log( sprintf( 'Disabling site %s.', $this->site_data->site_url ) ); - if ( \EE::docker()::docker_compose_down( $this->site['root'] ) ) { - $site->site_enabled = 0; - $site->save(); + if ( \EE::docker()::docker_compose_down( $this->site_data->site_fs_path ) ) { + $this->site_data->site_enabled = 0; + $this->site_data->save(); - \EE::success( sprintf( 'Site %s disabled.', $this->site['url'] ) ); + \EE::success( sprintf( 'Site %s disabled.', $this->site_data->site_url ) ); } else { - \EE::error( sprintf( 'There was error in disabling %s. Please check logs.', $this->site['url'] ) ); + \EE::error( sprintf( 'There was error in disabling %s. Please check logs.', $this->site_data->site_url ) ); } \EE\Utils\delem_log( 'site disable end' ); } @@ -287,13 +288,13 @@ public function down( $args, $assoc_args ) { public function restart( $args, $assoc_args, $whitelisted_containers = [] ) { \EE\Utils\delem_log( 'site restart start' ); - $args = EE\SiteUtils\auto_site_name( $args, 'site', __FUNCTION__ ); + $args = auto_site_name( $args, 'site', __FUNCTION__ ); $all = \EE\Utils\get_flag_value( $assoc_args, 'all' ); $no_service_specified = count( $assoc_args ) === 0; - $this->populate_site_info( $args ); + $this->site_data = get_site_info( $args ); - chdir( $this->site['root'] ); + chdir( $this->site_data['site_fs_path'] ); if ( $all || $no_service_specified ) { $containers = $whitelisted_containers; @@ -324,16 +325,16 @@ public function restart( $args, $assoc_args, $whitelisted_containers = [] ) { public function reload( $args, $assoc_args, $whitelisted_containers = [], $reload_commands = [] ) { \EE\Utils\delem_log( 'site reload start' ); - $args = EE\SiteUtils\auto_site_name( $args, 'site', __FUNCTION__ ); + $args = auto_site_name( $args, 'site', __FUNCTION__ ); $all = \EE\Utils\get_flag_value( $assoc_args, 'all' ); if ( ! array_key_exists( 'nginx', $reload_commands ) ) { $reload_commands['nginx'] = 'nginx sh -c \'nginx -t && service openresty reload\''; } $no_service_specified = count( $assoc_args ) === 0; - $this->populate_site_info( $args ); + $this->site_data = get_site_info( $args ); - chdir( $this->site['root'] ); + chdir( $this->site_data['site_fs_path'] ); if ( $all || $no_service_specified ) { $this->reload_services( $whitelisted_containers, $reload_commands ); @@ -352,31 +353,32 @@ public function reload( $args, $assoc_args, $whitelisted_containers = [], $reloa private function reload_services( $services, $reload_commands ) { foreach ( $services as $service ) { - EE\SiteUtils\run_compose_command( 'exec', $reload_commands[ $service ], 'reload', $service ); + \EE\Site\Utils\run_compose_command( 'exec', $reload_commands[ $service ], 'reload', $service ); } } /** * Runs the acme le registration and authorization. * - * @param string $site_name Name of the site for ssl. + * @param string $site_url Name of the site for ssl. * - * @throws Exception + * @throws \Exception */ - protected function inherit_certs( $site_name ) { - $parent_site_name = implode( '.', array_slice( explode( '.', $site_name ), 1 ) ); + protected function inherit_certs( $site_url ) { + + $parent_site_name = implode( '.', array_slice( explode( '.', $site_url ), 1 ) ); $parent_site = Site::find( $parent_site_name, [ 'site_ssl', 'site_ssl_wildcard' ] ); if ( ! $parent_site ) { - throw new Exception( 'Unable to find existing site: ' . $parent_site_name ); + throw new \Exception( 'Unable to find existing site: ' . $parent_site_name ); } if ( ! $parent_site->site_ssl ) { - throw new Exception( "Cannot inherit from $parent_site_name as site does not have SSL cert" . var_dump( $parent_site ) ); + throw new \Exception( "Cannot inherit from $parent_site_name as site does not have SSL cert" . var_dump( $parent_site ) ); } if ( ! $parent_site->site_ssl_wildcard ) { - throw new Exception( "Cannot inherit from $parent_site_name as site does not have wildcard SSL cert" ); + throw new \Exception( "Cannot inherit from $parent_site_name as site does not have wildcard SSL cert" ); } // We don't have to do anything now as nginx-proxy handles everything for us. @@ -386,24 +388,26 @@ protected function inherit_certs( $site_name ) { /** * Runs SSL procedure. * - * @param string $site_name Name of the site for ssl. - * @param string $site_root Webroot of the site. - * @param string $ssl_type Type of ssl cert to issue. - * @param bool $wildcard SSL with wildcard or not. + * @param string $site_url Name of the site for ssl. + * @param string $site_fs_path Webroot of the site. + * @param string $ssl_type Type of ssl cert to issue. + * @param bool $wildcard SSL with wildcard or not. * - * @throws \EE\ExitException If --ssl flag has unrecognized value + * @throws \EE\ExitException If --ssl flag has unrecognized value. + * @throws \Exception */ - protected function init_ssl( $site_name, $site_root, $ssl_type, $wildcard = false ) { + protected function init_ssl( $site_url, $site_fs_path, $ssl_type, $wildcard = false ) { + \EE::debug( 'Starting SSL procedure' ); if ( 'le' === $ssl_type ) { \EE::debug( 'Initializing LE' ); - $this->init_le( $site_name, $site_root, $wildcard ); + $this->init_le( $site_url, $site_fs_path, $wildcard ); } elseif ( 'inherit' === $ssl_type ) { if ( $wildcard ) { \EE::error( 'Cannot use --wildcard with --ssl=inherit', false ); } \EE::debug( 'Inheriting certs' ); - $this->inherit_certs( $site_name ); + $this->inherit_certs( $site_url ); } else { \EE::error( "Unrecognized value in --ssl flag: $ssl_type" ); } @@ -412,34 +416,33 @@ protected function init_ssl( $site_name, $site_root, $ssl_type, $wildcard = fals /** * Runs the acme le registration and authorization. * - * @param string $site_name Name of the site for ssl. - * @param string $site_root Webroot of the site. - * @param bool $wildcard SSL with wildcard or not. + * @param string $site_url Name of the site for ssl. + * @param string $site_fs_path Webroot of the site. + * @param bool $wildcard SSL with wildcard or not. */ - protected function init_le( $site_name, $site_root, $wildcard = false ) { + protected function init_le( $site_url, $site_fs_path, $wildcard = false ) { + \EE::debug( "Wildcard in init_le: $wildcard" ); - $this->site['url'] = $site_name; - $this->site['root'] = $site_root; - $this->wildcard = $wildcard; - $client = new Site_Letsencrypt(); - $this->le_mail = \EE::get_runner()->config['le-mail'] ?? \EE::input( 'Enter your mail id: ' ); + $this->site_data['site_url'] = $site_url; + $this->site_data['site_fs_path'] = $site_fs_path; + $this->site_data['site_ssl_wildcard'] = $wildcard; + $client = new Site_Letsencrypt(); + $this->le_mail = \EE::get_runner()->config['le-mail'] ?? \EE::input( 'Enter your mail id: ' ); \EE::get_runner()->ensure_present_in_config( 'le-mail', $this->le_mail ); if ( ! $client->register( $this->le_mail ) ) { - $this->ssl = null; + $this->site_data['site_ssl'] = null; return; } - $domains = $this->get_cert_domains( $site_name, $wildcard ); - - if ( ! $client->authorize( $domains, $this->site['root'], $wildcard ) ) { - $this->le = false; + $domains = $this->get_cert_domains( $site_url, $wildcard ); + if ( ! $client->authorize( $domains, $this->site_data['site_fs_path'], $wildcard ) ) { return; } if ( $wildcard ) { - echo \cli\Colors::colorize( '%YIMPORTANT:%n Run `ee site le ' . $this->site['url'] . '` once the dns changes have propogated to complete the certification generation and installation.', null ); + echo \cli\Colors::colorize( '%YIMPORTANT:%n Run `ee site le ' . $this->site_data['site_url'] . '` once the dns changes have propogated to complete the certification generation and installation.', null ); } else { $this->le( [], [] ); } @@ -448,19 +451,18 @@ protected function init_le( $site_name, $site_root, $wildcard = false ) { /** * Returns all domains required by cert * - * @param string $site_name Name of site + * @param string $site_url Name of site * @param $wildcard Wildcard cert required? * * @return array */ - private function get_cert_domains( string $site_name, $wildcard ): array { - $domains = [ $site_name ]; - $has_www = ( strpos( $site_name, 'www.' ) === 0 ); + private function get_cert_domains( string $site_url, $wildcard ): array { + $domains = [ $site_url ]; if ( $wildcard ) { - $domains[] = "*.{$site_name}"; + $domains[] = "*.{$site_url}"; } else { - $domains[] = $this->get_www_domain( $site_name ); + $domains[] = $this->get_www_domain( $site_url ); } return $domains; @@ -470,17 +472,18 @@ private function get_cert_domains( string $site_name, $wildcard ): array { * If the domain has www in it, returns a domain without www in it. * Else returns a domain with www in it. * - * @param string $site_name Name of site + * @param string $site_url Name of site * * @return string Domain name with or without www */ - private function get_www_domain( string $site_name ): string { - $has_www = ( strpos( $site_name, 'www.' ) === 0 ); + private function get_www_domain( string $site_url ): string { + + $has_www = ( strpos( $site_url, 'www.' ) === 0 ); if ( $has_www ) { - return ltrim( $site_name, 'www.' ); + return ltrim( $site_url, 'www.' ); } else { - return 'www.' . $site_name; + return 'www.' . $site_url; } } @@ -498,8 +501,8 @@ private function get_www_domain( string $site_name ): string { */ public function le( $args = [], $assoc_args = [] ) { - if ( ! isset( $this->site['url'] ) ) { - $this->populate_site_info( $args ); + if ( ! isset( $this->site_data['site_url'] ) ) { + $this->site_data = get_site_info( $args ); } if ( ! isset( $this->le_mail ) ) { @@ -507,42 +510,22 @@ public function le( $args = [], $assoc_args = [] ) { } $force = \EE\Utils\get_flag_value( $assoc_args, 'force' ); - $domains = $this->get_cert_domains( $this->site['url'], $this->wildcard ); + $domains = $this->get_cert_domains( $this->site_data['site_url'], $this->site_data['site_ssl_wildcard'] ); $client = new Site_Letsencrypt(); - if ( ! $client->check( $domains, $this->wildcard ) ) { - $this->ssl = null; + if ( ! $client->check( $domains, $this->site_data['site_ssl_wildcard'] ) ) { + $this->site_data['site_ssl'] = null; return; } - $san = array_values( array_diff( $domains, [ $this->site['url'] ] ) ); - $client->request( $this->site['url'], $san, $this->le_mail, $force ); - - if ( ! $this->wildcard ) { - $client->cleanup( $this->site['root'] ); - } - \EE::launch( 'docker exec ee-nginx-proxy sh -c "/app/docker-entrypoint.sh /usr/local/bin/docker-gen /app/nginx.tmpl /etc/nginx/conf.d/default.conf; /usr/sbin/nginx -s reload"' ); - } - - /** - * Populate basic site info from db. - */ - private function populate_site_info( $args ) { - - $this->site['url'] = \EE\Utils\remove_trailing_slash( $args[0] ); - $site = Site::find( $this->site['url'] ); - if ( $site ) { + $san = array_values( array_diff( $domains, [ $this->site_data['site_url'] ] ) ); + $client->request( $this->site_data['site_url'], $san, $this->le_mail, $force ); - $db_select = $site->site_url; - - $this->site['type'] = $site->site_type; - $this->site['root'] = $site->site_fs_path; - $this->ssl = $site->site_ssl; - $this->wildcard = $site->site_ssl_wildcard; - } else { - \EE::error( sprintf( 'Site %s does not exist.', $this->site['url'] ) ); + if ( ! $this->site_data['site_ssl_wildcard'] ) { + $client->cleanup( $this->site_data['site_fs_path'] ); } + reload_global_nginx_proxy(); } /** From 0744e019415ea9c3447a1c8ddfb7dc41f7492d7a Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Fri, 31 Aug 2018 17:32:28 +0530 Subject: [PATCH 68/81] Add get_site_info function Add reload_global_nginx_proxy function Update variable names Signed-off-by: Riddhesh Sanghvi --- src/helper/site-utils.php | 135 ++++++++++++++++++++++++-------------- 1 file changed, 85 insertions(+), 50 deletions(-) diff --git a/src/helper/site-utils.php b/src/helper/site-utils.php index 0092c19b..9b3c7f29 100644 --- a/src/helper/site-utils.php +++ b/src/helper/site-utils.php @@ -12,16 +12,17 @@ * @return bool|String Name of the site or false in failure. */ function get_site_name() { + $sites = Site::all( [ 'site_url' ] ); if ( ! empty( $sites ) ) { $cwd = getcwd(); $name_in_path = explode( '/', $cwd ); - $site_name = array_intersect( array_column( $sites, 'site_url' ), $name_in_path ); + $site_url = array_intersect( array_column( $sites, 'site_url' ), $name_in_path ); - if ( 1 === count( $site_name ) ) { - $name = reset( $site_name ); + if ( 1 === count( $site_url ) ) { + $name = reset( $site_url ); $path = Site::find( $name ); if ( $path ) { $site_path = $path->site_fs_path; @@ -58,12 +59,12 @@ function auto_site_name( $args, $command, $function, $arg_pos = 0 ) { return $args; } } - $site_name = get_site_name(); - if ( $site_name ) { + $site_url = get_site_name(); + if ( $site_url ) { if ( isset( $args[ $arg_pos ] ) ) { - EE::error( $args[ $arg_pos ] . " is not a valid site-name. Did you mean `ee $command $function $site_name`?" ); + EE::error( $args[ $arg_pos ] . " is not a valid site-name. Did you mean `ee $command $function $site_url`?" ); } - array_splice( $args, $arg_pos, 0, $site_name ); + array_splice( $args, $arg_pos, 0, $site_url ); } else { EE::error( "Could not find the site you wish to run $command $function command on.\nEither pass it as an argument: `ee $command $function ` \nor run `ee $command $function` from inside the site folder." ); } @@ -71,6 +72,33 @@ function auto_site_name( $args, $command, $function, $arg_pos = 0 ) { return $args; } +/** + * Populate basic site info from db. + * + * @param bool $site_enabled_check Check if site is enabled. Throw error message if not enabled. + * @param bool $exit_if_not_found Check if site exists. Throw error message if not. + * @param bool $return_array Return array of data or object. + * + * @return mixed $site_data Site data from db. + */ +function get_site_info( $args, $site_enabled_check = true, $exit_if_not_found = true, $return_array = true ) { + + $site_url = \EE\Utils\remove_trailing_slash( $args[0] ); + $data = Site::find( $site_url ); + $site_data = $return_array ? get_object_vars( $data ) : $data; + + + if ( ! $data->site_enabled && $site_enabled_check ) { + \EE::error( sprintf( 'Site %1$s is not enabled. Use `ee site up %1$s` to enable it.', $data->site_url ) ); + } + + if ( ! $site_data && $exit_if_not_found ) { + \EE::error( sprintf( 'Site %s does not exist.', $data->site_url ) ); + } + + return $site_data; +} + /** * Function to check all the required configurations needed to create the site. @@ -159,21 +187,21 @@ function generate_global_docker_compose_yml( Filesystem $fs ) { * Creates site root directory if does not exist. * Throws error if it does exist. * - * @param string $site_root Root directory of the site. - * @param string $site_name Name of the site. + * @param string $site_fs_path Root directory of the site. + * @param string $site_url Name of the site. */ -function create_site_root( $site_root, $site_name ) { +function create_site_root( $site_fs_path, $site_url ) { $fs = new Filesystem(); - if ( $fs->exists( $site_root ) ) { - EE::error( "Webroot directory for site $site_name already exists." ); + if ( $fs->exists( $site_fs_path ) ) { + EE::error( "Webroot directory for site $site_url already exists." ); } $whoami = EE::launch( 'whoami', false, true ); $terminal_username = rtrim( $whoami->stdout ); - $fs->mkdir( $site_root ); - $fs->chown( $site_root, $terminal_username ); + $fs->mkdir( $site_fs_path ); + $fs->chown( $site_fs_path, $terminal_username ); } /** @@ -188,30 +216,30 @@ function reload_proxy_configuration() { /** * Adds www to non-www redirection to site * - * @param string $site_name name of the site. - * @param bool $ssl enable ssl or not. - * @param bool $inherit inherit cert or not. + * @param string $site_url name of the site. + * @param bool $ssl enable ssl or not. + * @param bool $inherit inherit cert or not. */ -function add_site_redirects( string $site_name, bool $ssl, bool $inherit ) { +function add_site_redirects( string $site_url, bool $ssl, bool $inherit ) { $fs = new Filesystem(); $confd_path = EE_CONF_ROOT . '/nginx/conf.d/'; - $config_file_path = $confd_path . $site_name . '-redirect.conf'; - $has_www = strpos( $site_name, 'www.' ) === 0; - $cert_site_name = $site_name; + $config_file_path = $confd_path . $site_url . '-redirect.conf'; + $has_www = strpos( $site_url, 'www.' ) === 0; + $cert_site_name = $site_url; if ( $inherit ) { - $cert_site_name = implode( '.', array_slice( explode( '.', $site_name ), 1 ) ); + $cert_site_name = implode( '.', array_slice( explode( '.', $site_url ), 1 ) ); } if ( $has_www ) { - $server_name = ltrim( $site_name, '.www' ); + $server_name = ltrim( $site_url, '.www' ); } else { - $server_name = 'www.' . $site_name; + $server_name = 'www.' . $site_url; } $conf_data = [ - 'site_name' => $site_name, + 'site_name' => $site_url, 'cert_site_name' => $cert_site_name, 'server_name' => $server_name, 'ssl' => $ssl, @@ -224,17 +252,17 @@ function add_site_redirects( string $site_name, bool $ssl, bool $inherit ) { /** * Function to create entry in /etc/hosts. * - * @param string $site_name Name of the site. + * @param string $site_url Name of the site. */ -function create_etc_hosts_entry( $site_name ) { +function create_etc_hosts_entry( $site_url ) { - $host_line = LOCALHOST_IP . "\t$site_name"; + $host_line = LOCALHOST_IP . "\t$site_url"; $etc_hosts = file_get_contents( '/etc/hosts' ); - if ( ! preg_match( "/\s+$site_name\$/m", $etc_hosts ) ) { + if ( ! preg_match( "/\s+$site_url\$/m", $etc_hosts ) ) { if ( EE::exec( "/bin/bash -c 'echo \"$host_line\" >> /etc/hosts'" ) ) { EE::success( 'Host entry successfully added.' ); } else { - EE::warning( "Failed to add $site_name in host entry, Please do it manually!" ); + EE::warning( "Failed to add $site_url in host entry, Please do it manually!" ); } } else { EE::log( 'Host entry already exists.' ); @@ -245,18 +273,18 @@ function create_etc_hosts_entry( $site_name ) { /** * Checking site is running or not. * - * @param string $site_name Name of the site. + * @param string $site_url Name of the site. * * @throws \Exception when fails to connect to site. */ -function site_status_check( $site_name ) { +function site_status_check( $site_url ) { EE::log( 'Checking and verifying site-up status. This may take some time.' ); - $httpcode = get_curl_info( $site_name ); + $httpcode = get_curl_info( $site_url ); $i = 0; while ( 200 !== $httpcode && 302 !== $httpcode && 301 !== $httpcode ) { - EE::debug( "$site_name status httpcode: $httpcode" ); - $httpcode = get_curl_info( $site_name ); + EE::debug( "$site_url status httpcode: $httpcode" ); + $httpcode = get_curl_info( $site_url ); echo '.'; sleep( 2 ); if ( $i ++ > 60 ) { @@ -297,19 +325,19 @@ function get_curl_info( $url, $port = 80, $port_info = false ) { /** * Function to pull the latest images and bring up the site containers. * - * @param string $site_root Root directory of the site. - * @param array $containers The minimum required conatainers to start the site. Default null, leads to starting of all - * containers. + * @param string $site_fs_path Root directory of the site. + * @param array $containers The minimum required conatainers to start the site. Default null, leads to starting of + * all containers. * * @throws \Exception when docker-compose up fails. */ -function start_site_containers( $site_root, $containers = [] ) { +function start_site_containers( $site_fs_path, $containers = [] ) { EE::log( 'Pulling latest images. This may take some time.' ); - chdir( $site_root ); + chdir( $site_fs_path ); EE::exec( 'docker-compose pull' ); EE::log( 'Starting site\'s services.' ); - if ( ! EE::docker()::docker_compose_up( $site_root, $containers ) ) { + if ( ! EE::docker()::docker_compose_up( $site_fs_path, $containers ) ) { throw new \Exception( 'There was some error in docker-compose up.' ); } } @@ -335,17 +363,17 @@ function run_compose_command( $action, $container, $action_to_display = null, $s /** * Function to copy and configure files needed for postfix. * - * @param string $site_name Name of the site to configure postfix files for. + * @param string $site_url Name of the site to configure postfix files for. * @param string $site_conf_dir Configuration directory of the site `site_root/config`. */ -function set_postfix_files( $site_name, $site_conf_dir ) { +function set_postfix_files( $site_url, $site_conf_dir ) { $fs = new Filesystem(); $fs->mkdir( $site_conf_dir . '/postfix' ); $fs->mkdir( $site_conf_dir . '/postfix/ssl' ); $ssl_dir = $site_conf_dir . '/postfix/ssl'; - if ( ! EE::exec( sprintf( "openssl req -new -x509 -nodes -days 365 -subj \"/CN=smtp.%s\" -out $ssl_dir/server.crt -keyout $ssl_dir/server.key", $site_name ) ) + if ( ! EE::exec( sprintf( "openssl req -new -x509 -nodes -days 365 -subj \"/CN=smtp.%s\" -out $ssl_dir/server.crt -keyout $ssl_dir/server.key", $site_url ) ) && EE::exec( "chmod 0600 $ssl_dir/server.key" ) ) { throw new Exception( 'Unable to generate ssl key for postfix' ); } @@ -354,18 +382,25 @@ function set_postfix_files( $site_name, $site_conf_dir ) { /** * Function to execute docker-compose exec calls to postfix to get it configured and running for the site. * - * @param string $site_name Name of the for which postfix has to be configured. - * @param strin $site_root Site root. + * @param string $site_url Name of the for which postfix has to be configured. + * @param string $site_fs_path Site root. */ -function configure_postfix( $site_name, $site_root ) { +function configure_postfix( $site_url, $site_fs_path ) { - chdir( $site_root ); + chdir( $site_fs_path ); EE::exec( 'docker-compose exec postfix postconf -e \'relayhost =\'' ); EE::exec( 'docker-compose exec postfix postconf -e \'smtpd_recipient_restrictions = permit_mynetworks\'' ); - $launch = EE::launch( sprintf( 'docker inspect -f \'{{ with (index .IPAM.Config 0) }}{{ .Subnet }}{{ end }}\' %s', $site_name ) ); + $launch = EE::launch( sprintf( 'docker inspect -f \'{{ with (index .IPAM.Config 0) }}{{ .Subnet }}{{ end }}\' %s', $site_url ) ); $subnet_cidr = trim( $launch->stdout ); EE::exec( sprintf( 'docker-compose exec postfix postconf -e \'mynetworks = %s 127.0.0.0/8\'', $subnet_cidr ) ); - EE::exec( sprintf( 'docker-compose exec postfix postconf -e \'myhostname = %s\'', $site_name ) ); + EE::exec( sprintf( 'docker-compose exec postfix postconf -e \'myhostname = %s\'', $site_url ) ); EE::exec( 'docker-compose exec postfix postconf -e \'syslog_name = $myhostname\'' ); EE::exec( 'docker-compose restart postfix' ); } + +/** + * Reload the global nginx proxy. + */ +function reload_global_nginx_proxy() { + \EE::launch( sprintf( 'docker exec %s sh -c "/app/docker-entrypoint.sh /usr/local/bin/docker-gen /app/nginx.tmpl /etc/nginx/conf.d/default.conf; /usr/sbin/nginx -s reload"', EE_PROXY_TYPE ) ); +} From cd535c7f861b50d5f6aafe14eb8b1e0f876781a4 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Fri, 31 Aug 2018 17:33:26 +0530 Subject: [PATCH 69/81] Refactor db related code and calls in site-type html Signed-off-by: Riddhesh Sanghvi --- src/site-type/html.php | 144 ++++++++++++++++------------------------- 1 file changed, 57 insertions(+), 87 deletions(-) diff --git a/src/site-type/html.php b/src/site-type/html.php index 5c279b5a..ecd5e731 100644 --- a/src/site-type/html.php +++ b/src/site-type/html.php @@ -2,6 +2,13 @@ declare( ticks=1 ); +namespace EE\Site\Type; + +use \EE\Model\Site; +use \Symfony\Component\Filesystem\Filesystem; +use function \EE\Site\Utils\auto_site_name; +use function \EE\Site\Utils\get_site_info; + /** * Creates a simple html Website. * @@ -12,19 +19,12 @@ * * @package ee-cli */ - -namespace EE\Site\Type; - -use \EE\Model\Site; - -use \Symfony\Component\Filesystem\Filesystem; - class HTML extends EE_Site_Command { /** - * @var array $site Associative array containing essential site related information. + * @var array $site_data Associative array containing essential site related information. */ - private $site; + private $site_data; /** * @var object $docker Object to access `\EE::docker()` functions. @@ -42,19 +42,9 @@ class HTML extends EE_Site_Command { private $logger; /** - * @var bool $ssl Whether the site is has SSL enabled. + * @var bool $skip_status_check To skip site status check pre-installation. */ - private $ssl; - - /** - * @var bool $ssl_wildcard Whether the site SSL is wildcard. - */ - private $ssl_wildcard; - - /** - * @var bool $skip_chk To skip site status check pre-installation. - */ - private $skip_chk; + private $skip_status_check; /** * @var Filesystem $fs Symfony Filesystem object. @@ -95,19 +85,18 @@ public function create( $args, $assoc_args ) { \EE::warning( 'This is a beta version. Please don\'t use it in production.' ); $this->logger->debug( 'args:', $args ); $this->logger->debug( 'assoc_args:', empty( $assoc_args ) ? [ 'NULL' ] : $assoc_args ); - $this->site['url'] = strtolower( \EE\Utils\remove_trailing_slash( $args[0] ) ); - $this->site['type'] = \EE\Utils\get_flag_value( $assoc_args, 'type', 'html' ); - if ( 'html' !== $this->site['type'] ) { - \EE::error( sprintf( 'Invalid site-type: %s', $this->site['type'] ) ); + $this->site_data['site_url'] = strtolower( \EE\Utils\remove_trailing_slash( $args[0] ) ); + $this->site_data['site_type'] = \EE\Utils\get_flag_value( $assoc_args, 'type', 'html' ); + if ( 'html' !== $this->site_data['site_type'] ) { + \EE::error( sprintf( 'Invalid site-type: %s', $this->site_data['site_type'] ) ); } - - if ( Site::find( $this->site['url'] ) ) { - \EE::error( sprintf( "Site %1\$s already exists. If you want to re-create it please delete the older one using:\n`ee site delete %1\$s`", $this->site['url'] ) ); + if ( Site::find( $this->site_data['site_url'] ) ) { + \EE::error( sprintf( "Site %1\$s already exists. If you want to re-create it please delete the older one using:\n`ee site delete %1\$s`", $this->site_data['site_url'] ) ); } - $this->ssl = \EE\Utils\get_flag_value( $assoc_args, 'ssl' ); - $this->ssl_wildcard = \EE\Utils\get_flag_value( $assoc_args, 'wildcard' ); - $this->skip_chk = \EE\Utils\get_flag_value( $assoc_args, 'skip-status-check' ); + $this->site_data['site_ssl'] = \EE\Utils\get_flag_value( $assoc_args, 'ssl' ); + $this->site_data['site_ssl_wildcard'] = \EE\Utils\get_flag_value( $assoc_args, 'wildcard' ); + $this->skip_status_check = \EE\Utils\get_flag_value( $assoc_args, 'skip-status-check' ); \EE\Site\Utils\init_checks(); @@ -126,20 +115,20 @@ public function create( $args, $assoc_args ) { public function info( $args, $assoc_args ) { \EE\Utils\delem_log( 'site info start' ); - if ( ! isset( $this->site['url'] ) ) { - $args = \EE\Site\Utils\auto_site_name( $args, 'site', __FUNCTION__ ); - $this->populate_site_info( $args ); + if ( ! isset( $this->site_data['site_url'] ) ) { + $args = auto_site_name( $args, 'site', __FUNCTION__ ); + $this->site_data = get_site_info( $args, false ); } - $ssl = $this->ssl ? 'Enabled' : 'Not Enabled'; - $prefix = ( $this->ssl ) ? 'https://' : 'http://'; + $ssl = $this->site_data['site_ssl'] ? 'Enabled' : 'Not Enabled'; + $prefix = ( $this->site_data['site_ssl'] ) ? 'https://' : 'http://'; $info = [ - [ 'Site', $prefix . $this->site['url'] ], - [ 'Site Root', $this->site['root'] ], + [ 'Site', $prefix . $this->site_data['site_url'] ], + [ 'Site Root', $this->site_data['site_fs_path'] ], [ 'SSL', $ssl ], ]; - if ( $this->ssl ) { - $info[] = [ 'SSL Wildcard', $this->ssl_wildcard ? 'Yes' : 'No' ]; + if ( $this->site_data['site_ssl'] ) { + $info[] = [ 'SSL Wildcard', $this->site_data['site_ssl_wildcard'] ? 'Yes' : 'No' ]; } \EE\Utils\format_table( $info ); @@ -153,24 +142,24 @@ public function info( $args, $assoc_args ) { */ private function configure_site_files() { - $site_conf_dir = $this->site['root'] . '/config'; - $site_docker_yml = $this->site['root'] . '/docker-compose.yml'; - $site_conf_env = $this->site['root'] . '/.env'; + $site_conf_dir = $this->site_data['site_fs_path'] . '/config'; + $site_docker_yml = $this->site_data['site_fs_path'] . '/docker-compose.yml'; + $site_conf_env = $this->site_data['site_fs_path'] . '/.env'; $site_nginx_default_conf = $site_conf_dir . '/nginx/default.conf'; - $site_src_dir = $this->site['root'] . '/app/src'; + $site_src_dir = $this->site_data['site_fs_path'] . '/app/src'; $process_user = posix_getpwuid( posix_geteuid() ); - \EE::log( sprintf( 'Creating site %s.', $this->site['url'] ) ); + \EE::log( sprintf( 'Creating site %s.', $this->site_data['site_url'] ) ); \EE::log( 'Copying configuration files.' ); $filter = []; - $filter[] = $this->site['type']; + $filter[] = $this->site_data['site_type']; $site_docker = new Site_HTML_Docker(); $docker_compose_content = $site_docker->generate_docker_compose_yml( $filter ); - $default_conf_content = $default_conf_content = \EE\Utils\mustache_render( SITE_TEMPLATE_ROOT . '/config/nginx/default.conf.mustache', [ 'server_name' => $this->site['url'] ] ); + $default_conf_content = $default_conf_content = \EE\Utils\mustache_render( SITE_TEMPLATE_ROOT . '/config/nginx/default.conf.mustache', [ 'server_name' => $this->site_data['site_url'] ] ); $env_data = [ - 'virtual_host' => $this->site['url'], + 'virtual_host' => $this->site_data['site_url'], 'user_id' => $process_user['uid'], 'group_id' => $process_user['gid'], ]; @@ -185,7 +174,7 @@ private function configure_site_files() { $index_data = [ 'version' => 'v' . EE_VERSION, - 'site_src_root' => $this->site['root'] . '/app/src', + 'site_src_root' => $this->site_data['site_fs_path'] . '/app/src', ]; $index_html = \EE\Utils\mustache_render( SITE_TEMPLATE_ROOT . '/index.html.mustache', $index_data ); $this->fs->mkdir( $site_src_dir ); @@ -202,19 +191,19 @@ private function configure_site_files() { */ private function create_site() { - $this->site['root'] = WEBROOT . $this->site['url']; - $this->level = 1; + $this->site_data['site_fs_path'] = WEBROOT . $this->site_data['site_url']; + $this->level = 1; try { - \EE\Site\Utils\create_site_root( $this->site['root'], $this->site['url'] ); + \EE\Site\Utils\create_site_root( $this->site_data['site_fs_path'], $this->site_data['site_url'] ); $this->level = 3; $this->configure_site_files(); - \EE\Site\Utils\start_site_containers( $this->site['root'] ); + \EE\Site\Utils\start_site_containers( $this->site_data['site_fs_path'] ); - \EE\Site\Utils\create_etc_hosts_entry( $this->site['url'] ); - if ( ! $this->skip_chk ) { + \EE\Site\Utils\create_etc_hosts_entry( $this->site_data['site_url'] ); + if ( ! $this->skip_status_check ) { $this->level = 4; - \EE\Site\Utils\site_status_check( $this->site['url'] ); + \EE\Site\Utils\site_status_check( $this->site_data['site_url'] ); } /* @@ -227,19 +216,19 @@ private function create_site() { * We add redirection config two times in case of ssl as we need http redirection * when certs are being requested and http+https redirection after we have certs. */ - \EE\Site\Utils\add_site_redirects( $this->site['url'], false, 'inherit' === $this->ssl ); + \EE\Site\Utils\add_site_redirects( $this->site_data['site_url'], false, 'inherit' === $this->site_data['site_ssl'] ); \EE\Site\Utils\reload_proxy_configuration(); - if ( $this->ssl ) { - $this->init_ssl( $this->site['url'], $this->site['root'], $this->ssl, $this->ssl_wildcard ); - \EE\Site\Utils\add_site_redirects( $this->site['url'], true, 'inherit' === $this->ssl ); + if ( $this->site_data['site_ssl'] ) { + $this->init_ssl( $this->site_data['site_url'], $this->site_data['site_fs_path'], $this->site_data['site_ssl'], $this->site_data['site_ssl_wildcard'] ); + \EE\Site\Utils\add_site_redirects( $this->site_data['site_url'], true, 'inherit' === $this->site_data['site_ssl'] ); \EE\Site\Utils\reload_proxy_configuration(); } } catch ( \Exception $e ) { $this->catch_clean( $e ); } - $this->info( [ $this->site['url'] ], [] ); + $this->info( [ $this->site_data['site_url'] ], [] ); $this->create_site_db_entry(); } @@ -248,13 +237,13 @@ private function create_site() { */ private function create_site_db_entry() { - $ssl = $this->ssl ? 1 : 0; - $ssl_wildcard = $this->ssl_wildcard ? 1 : 0; + $ssl = $this->site_data['site_ssl'] ? 1 : 0; + $ssl_wildcard = $this->site_data['site_ssl_wildcard'] ? 1 : 0; $site = Site::create( [ - 'site_url' => $this->site['url'], - 'site_type' => $this->site['type'], - 'site_fs_path' => $this->site['root'], + 'site_url' => $this->site_data['site_url'], + 'site_type' => $this->site_data['site_type'], + 'site_fs_path' => $this->site_data['site_fs_path'], 'site_ssl' => $ssl, 'site_ssl_wildcard' => $ssl_wildcard, 'created_on' => date( 'Y-m-d H:i:s', time() ), @@ -271,25 +260,6 @@ private function create_site_db_entry() { } } - /** - * Populate basic site info from db. - */ - private function populate_site_info( $args ) { - - $this->site['url'] = \EE\Utils\remove_trailing_slash( $args[0] ); - - $site = Site::find( $this->site['url'] ); - - if ( $site ) { - $this->site['type'] = $site->site_type; - $this->site['root'] = $site->site_fs_path; - $this->ssl = $site->site_ssl; - $this->ssl_wildcard = $site->site_ssl_wildcard; - } else { - \EE::error( sprintf( 'Site %s does not exist.', $this->site['url'] ) ); - } - } - /** * @inheritdoc */ @@ -316,7 +286,7 @@ private function catch_clean( $e ) { \EE\Utils\delem_log( 'site cleanup start' ); \EE::warning( $e->getMessage() ); \EE::warning( 'Initiating clean-up.' ); - $this->delete_site( $this->level, $this->site['url'], $this->site['root'] ); + $this->delete_site( $this->level, $this->site_data['site_url'], $this->site_data['site_fs_path'] ); \EE\Utils\delem_log( 'site cleanup end' ); exit; } @@ -328,7 +298,7 @@ protected function rollback() { \EE::warning( 'Exiting gracefully after rolling back. This may take some time.' ); if ( $this->level > 0 ) { - $this->delete_site( $this->level, $this->site['url'], $this->site['root'] ); + $this->delete_site( $this->level, $this->site_data['site_url'], $this->site_data['site_fs_path'] ); } \EE::success( 'Rollback complete. Exiting now.' ); exit; From f18d9221bcdbac480f9b3a6065ae1d65f8a765ca Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Fri, 31 Aug 2018 18:20:42 +0530 Subject: [PATCH 70/81] Update ci prepare Signed-off-by: Riddhesh Sanghvi --- ci/prepare.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ci/prepare.sh b/ci/prepare.sh index 3535cfce..9c4387ea 100755 --- a/ci/prepare.sh +++ b/ci/prepare.sh @@ -15,11 +15,16 @@ cd easyengine rm -r features cp -R ../$TEST_COMMAND/features . +# Update repo branches +if [[ "$TRAVIS_BRANCH" != "master" ]]; then + sed -i 's/\(easyengine\/.*\):\ \".*\"/\1:\ \"dev-develop\"/' composer.json +fi + # Install composer dependencies and update them for tests composer update # Place the command inside EE repo -rm -r vendor/easyengine/$TEST_COMMAND +sudo rm -rf vendor/easyengine/$TEST_COMMAND cp -R ../$TEST_COMMAND vendor/easyengine/ # Create phar and test it From 510cfcee0569a31817f5f314e2c2749a904d95ab Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Fri, 31 Aug 2018 19:03:30 +0530 Subject: [PATCH 71/81] Typecast object to array Signed-off-by: Riddhesh Sanghvi --- src/helper/site-utils.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/helper/site-utils.php b/src/helper/site-utils.php index 9b3c7f29..e85720fc 100644 --- a/src/helper/site-utils.php +++ b/src/helper/site-utils.php @@ -83,16 +83,17 @@ function auto_site_name( $args, $command, $function, $arg_pos = 0 ) { */ function get_site_info( $args, $site_enabled_check = true, $exit_if_not_found = true, $return_array = true ) { - $site_url = \EE\Utils\remove_trailing_slash( $args[0] ); - $data = Site::find( $site_url ); - $site_data = $return_array ? get_object_vars( $data ) : $data; + $site_url = \EE\Utils\remove_trailing_slash( $args[0] ); + $data = Site::find( $site_url ); + $array_data = ( array ) $data; + $site_data = $return_array ? reset( $array_data ) : $data; if ( ! $data->site_enabled && $site_enabled_check ) { \EE::error( sprintf( 'Site %1$s is not enabled. Use `ee site up %1$s` to enable it.', $data->site_url ) ); } - if ( ! $site_data && $exit_if_not_found ) { + if ( ! $data && $exit_if_not_found ) { \EE::error( sprintf( 'Site %s does not exist.', $data->site_url ) ); } From b5556bf80b56244e624786d7196957f331f45c44 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Fri, 31 Aug 2018 19:14:35 +0530 Subject: [PATCH 72/81] Fix namespace usage Signed-off-by: Riddhesh Sanghvi --- src/helper/class-ee-site.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helper/class-ee-site.php b/src/helper/class-ee-site.php index d99f2612..562a522e 100644 --- a/src/helper/class-ee-site.php +++ b/src/helper/class-ee-site.php @@ -303,7 +303,7 @@ public function restart( $args, $assoc_args, $whitelisted_containers = [] ) { } foreach ( $containers as $container ) { - EE\Siteutils\run_compose_command( 'restart', $container ); + \EE\Site\Utils\run_compose_command( 'restart', $container ); } \EE\Utils\delem_log( 'site restart stop' ); } From 708137085bea94d2d736f09140e2cb6769b69d83 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Tue, 4 Sep 2018 18:53:39 +0530 Subject: [PATCH 73/81] Update site-status check for auth enabled enviournment Signed-off-by: Riddhesh Sanghvi --- src/helper/site-utils.php | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/helper/site-utils.php b/src/helper/site-utils.php index e85720fc..0d3262e4 100644 --- a/src/helper/site-utils.php +++ b/src/helper/site-utils.php @@ -283,15 +283,22 @@ function site_status_check( $site_url ) { EE::log( 'Checking and verifying site-up status. This may take some time.' ); $httpcode = get_curl_info( $site_url ); $i = 0; + $auth = false; while ( 200 !== $httpcode && 302 !== $httpcode && 301 !== $httpcode ) { EE::debug( "$site_url status httpcode: $httpcode" ); - $httpcode = get_curl_info( $site_url ); + if ( 401 === $httpcode ) { + $user_pass = get_global_auth(); + $auth = $user_pass['username'] . ':' . $user_pass['password']; + } + $httpcode = get_curl_info( $site_url, 80, false, $auth ); echo '.'; sleep( 2 ); if ( $i ++ > 60 ) { break; } } + EE::debug( "$site_url status httpcode: $httpcode" ); + echo PHP_EOL; if ( 200 !== $httpcode && 302 !== $httpcode && 301 !== $httpcode ) { throw new \Exception( 'Problem connecting to site!' ); } @@ -304,10 +311,11 @@ function site_status_check( $site_url ) { * @param string $url url to get info about. * @param int $port The port to check. * @param bool $port_info Return port info or httpcode. + * @param mixed $auth Send http auth with passed value if not false. * * @return bool|int port occupied or httpcode. */ -function get_curl_info( $url, $port = 80, $port_info = false ) { +function get_curl_info( $url, $port = 80, $port_info = false, $auth = false ) { $ch = curl_init( $url ); curl_setopt( $ch, CURLOPT_HEADER, true ); @@ -315,6 +323,9 @@ function get_curl_info( $url, $port = 80, $port_info = false ) { curl_setopt( $ch, CURLOPT_NOBODY, true ); curl_setopt( $ch, CURLOPT_TIMEOUT, 10 ); curl_setopt( $ch, CURLOPT_PORT, $port ); + if ( $auth ) { + curl_setopt( $ch, CURLOPT_USERPWD, $auth ); + } curl_exec( $ch ); if ( $port_info ) { return empty( curl_getinfo( $ch, CURLINFO_PRIMARY_IP ) ); @@ -405,3 +416,27 @@ function configure_postfix( $site_url, $site_fs_path ) { function reload_global_nginx_proxy() { \EE::launch( sprintf( 'docker exec %s sh -c "/app/docker-entrypoint.sh /usr/local/bin/docker-gen /app/nginx.tmpl /etc/nginx/conf.d/default.conf; /usr/sbin/nginx -s reload"', EE_PROXY_TYPE ) ); } + +/** + * Get global auth if it exists. + */ +function get_global_auth() { + if ( ! class_exists( '\EE\Model\Auth' ) ) { + return false; + } + + $auth = \EE\Model\Auth::where( [ + 'site_url' => 'default', + 'scope' => 'site', + ] ); + + if ( empty( $auth ) ) { + return false; + } + + return [ + 'username' => $auth[0]->username, + 'password' => $auth[0]->password, + ]; + +} From 9e604f8c30356c92ad1936e096aae7bcf6d75e70 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Wed, 5 Sep 2018 14:04:22 +0530 Subject: [PATCH 74/81] Update mounting of html folder for letsencrypt Signed-off-by: Riddhesh Sanghvi --- src/helper/site-utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helper/site-utils.php b/src/helper/site-utils.php index 0d3262e4..74329c9a 100644 --- a/src/helper/site-utils.php +++ b/src/helper/site-utils.php @@ -171,7 +171,7 @@ function generate_global_docker_compose_yml( Filesystem $fs ) { EE_CONF_ROOT . '/nginx/conf.d:/etc/nginx/conf.d', EE_CONF_ROOT . '/nginx/htpasswd:/etc/nginx/htpasswd', EE_CONF_ROOT . '/nginx/vhost.d:/etc/nginx/vhost.d', - '/usr/share/nginx/html', + EE_CONF_ROOT . '/nginx/html:/usr/share/nginx/html', '/var/run/docker.sock:/tmp/docker.sock:ro', ], 'networks' => [ From fc8d97da747cfdb43aa1b4addac40ef4b9e5548e Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Wed, 5 Sep 2018 14:21:32 +0530 Subject: [PATCH 75/81] Update challange file creation and cleanup Signed-off-by: Riddhesh Sanghvi --- src/helper/Site_Letsencrypt.php | 60 ++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/src/helper/Site_Letsencrypt.php b/src/helper/Site_Letsencrypt.php index 6fd81117..30d699e1 100644 --- a/src/helper/Site_Letsencrypt.php +++ b/src/helper/Site_Letsencrypt.php @@ -34,6 +34,7 @@ use League\Flysystem\Adapter\Local; use League\Flysystem\Adapter\NullAdapter; use GuzzleHttp\Client; +use function \EE\Site\Utils\reload_global_nginx_proxy; class Site_Letsencrypt { @@ -109,13 +110,19 @@ private function getSecureHttpClient() { ); } - + /** + * Function to register mail to letsencrypt. + * + * @param string $email Mail id to be registered. + * + * @return bool Success. + */ public function register( $email ) { try { $this->client->registerAccount( null, $email ); } catch ( \Exception $e ) { \EE::warning( $e->getMessage() ); - \EE::warning( 'It seems you\'re in local environment or there is some issue with network, please check logs. Skipping letsencrypt.' ); + \EE::warning( 'It seems you\'re in local environment or used invalid email or there is some issue with network, please check logs. Skipping letsencrypt.' ); return false; } @@ -124,7 +131,15 @@ public function register( $email ) { return true; } - public function authorize( Array $domains, $site_root, $wildcard = false ) { + /** + * Function to authorize the letsencrypt request and get the token for challenge. + * + * @param array $domains Domains to be authorized. + * @param bool $wildcard Is the authorization for wildcard or not. + * + * @return bool Success. + */ + public function authorize( Array $domains, $wildcard = false ) { $solver = $wildcard ? new SimpleDnsSolver( null, new ConsoleOutput() ) : new SimpleHttpSolver(); $solverName = $wildcard ? 'dns-01' : 'http-01'; try { @@ -165,10 +180,17 @@ public function authorize( Array $domains, $site_root, $wildcard = false ) { if ( ! $wildcard ) { $token = $authorizationChallenge->toArray()['token']; $payload = $authorizationChallenge->toArray()['payload']; - \EE::launch( "mkdir -p $site_root/app/src/.well-known/acme-challenge/" ); - \EE::debug( "Creating challange file $site_root/app/src/.well-known/acme-challenge/$token" ); - file_put_contents( "$site_root/app/src/.well-known/acme-challenge/$token", $payload ); - \EE::launch( "chown www-data: $site_root/app/src/.well-known/acme-challenge/$token" ); + + $fs = new \Symfony\Component\Filesystem\Filesystem(); + $fs->copy( SITE_TEMPLATE_ROOT . '/vhost.d_default_letsencrypt.mustache', EE_CONF_ROOT . '/nginx/vhost.d/default' ); + $challange_dir = EE_CONF_ROOT . '/nginx/html'; + if ( ! $fs->exists( $challange_dir ) ) { + $fs->mkdir( $challange_dir ); + } + $challange_file = $challange_dir . '/' . $token; + \EE::debug( 'Creating challange file ' . $challange_file ); + $fs->dumpFile( $challange_file, $payload ); + reload_global_nginx_proxy(); } } @@ -519,11 +541,25 @@ public function status() { $table->render(); } - public function cleanup( $site_root ) { - $challange_dir = "$site_root/app/src/.well-known"; - if ( file_exists( "$site_root/app/src/.well-known" ) ) { - \EE::debug( 'Cleaning up webroot files.' ); - \EE\Utils\delete_dir( $challange_dir ); + /** + * Cleanup created challenge files and specific rule sets for it. + */ + public function cleanup() { + + $fs = new \Symfony\Component\Filesystem\Filesystem(); + + $challange_dir = EE_CONF_ROOT . '/nginx/html/'; + $challange_rule_file = EE_CONF_ROOT . '/nginx/vhost.d/default'; + if ( $fs->exsits( $challange_rule_file ) ) { + $fs->remove( $challange_rule_file ); + } + $files = scandir( $challange_dir ); + if ( empty( $files ) ) { + return; + } + $challange_files = array_slice( $files, 2 ); + foreach ( $challange_files as $challange_file ) { + $fs->remove( $challange_dir . $challange_file ); } } } From a549c1845a24339a948a676831ed15bfe0422238 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Wed, 5 Sep 2018 14:49:18 +0530 Subject: [PATCH 76/81] Update challange directory Signed-off-by: Riddhesh Sanghvi --- src/helper/Site_Letsencrypt.php | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/helper/Site_Letsencrypt.php b/src/helper/Site_Letsencrypt.php index 30d699e1..31b993c0 100644 --- a/src/helper/Site_Letsencrypt.php +++ b/src/helper/Site_Letsencrypt.php @@ -183,7 +183,7 @@ public function authorize( Array $domains, $wildcard = false ) { $fs = new \Symfony\Component\Filesystem\Filesystem(); $fs->copy( SITE_TEMPLATE_ROOT . '/vhost.d_default_letsencrypt.mustache', EE_CONF_ROOT . '/nginx/vhost.d/default' ); - $challange_dir = EE_CONF_ROOT . '/nginx/html'; + $challange_dir = EE_CONF_ROOT . '/nginx/html/.well-known/acme-challenge'; if ( ! $fs->exists( $challange_dir ) ) { $fs->mkdir( $challange_dir ); } @@ -548,18 +548,13 @@ public function cleanup() { $fs = new \Symfony\Component\Filesystem\Filesystem(); - $challange_dir = EE_CONF_ROOT . '/nginx/html/'; + $challange_dir = EE_CONF_ROOT . '/nginx/html/.well-known'; $challange_rule_file = EE_CONF_ROOT . '/nginx/vhost.d/default'; - if ( $fs->exsits( $challange_rule_file ) ) { + if ( $fs->exists( $challange_rule_file ) ) { $fs->remove( $challange_rule_file ); } - $files = scandir( $challange_dir ); - if ( empty( $files ) ) { - return; - } - $challange_files = array_slice( $files, 2 ); - foreach ( $challange_files as $challange_file ) { - $fs->remove( $challange_dir . $challange_file ); + if ( $fs->exists( $challange_dir ) ) { + $fs->remove( $challange_dir ); } } } From a0d2227ab1f825c234d6b888b4cca56021bd0e49 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Wed, 5 Sep 2018 14:54:33 +0530 Subject: [PATCH 77/81] Update function calls after auth changes Signed-off-by: Riddhesh Sanghvi --- src/helper/class-ee-site.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/helper/class-ee-site.php b/src/helper/class-ee-site.php index 562a522e..a95b27b2 100644 --- a/src/helper/class-ee-site.php +++ b/src/helper/class-ee-site.php @@ -422,7 +422,7 @@ protected function init_ssl( $site_url, $site_fs_path, $ssl_type, $wildcard = fa */ protected function init_le( $site_url, $site_fs_path, $wildcard = false ) { - \EE::debug( "Wildcard in init_le: $wildcard" ); + \EE::debug( 'Wildcard in init_le: ' . ( bool ) $wildcard ); $this->site_data['site_url'] = $site_url; $this->site_data['site_fs_path'] = $site_fs_path; @@ -438,7 +438,7 @@ protected function init_le( $site_url, $site_fs_path, $wildcard = false ) { $domains = $this->get_cert_domains( $site_url, $wildcard ); - if ( ! $client->authorize( $domains, $this->site_data['site_fs_path'], $wildcard ) ) { + if ( ! $client->authorize( $domains, $wildcard ) ) { return; } if ( $wildcard ) { @@ -523,7 +523,7 @@ public function le( $args = [], $assoc_args = [] ) { $client->request( $this->site_data['site_url'], $san, $this->le_mail, $force ); if ( ! $this->site_data['site_ssl_wildcard'] ) { - $client->cleanup( $this->site_data['site_fs_path'] ); + $client->cleanup(); } reload_global_nginx_proxy(); } From 5c1bb69d0950144342e798b73505255baf8d85da Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Wed, 5 Sep 2018 14:55:15 +0530 Subject: [PATCH 78/81] Add vhost.d rule file template for http challange files Signed-off-by: Riddhesh Sanghvi --- templates/vhost.d_default_letsencrypt.mustache | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 templates/vhost.d_default_letsencrypt.mustache diff --git a/templates/vhost.d_default_letsencrypt.mustache b/templates/vhost.d_default_letsencrypt.mustache new file mode 100644 index 00000000..14daa7e4 --- /dev/null +++ b/templates/vhost.d_default_letsencrypt.mustache @@ -0,0 +1,7 @@ +location ^~ /.well-known/acme-challenge/ { + auth_basic off; + allow all; + root /usr/share/nginx/html; + try_files $uri =404; + break; +} From 920a78ac6f3c033cf8e580f2f7cc1e907ffd2254 Mon Sep 17 00:00:00 2001 From: sagar Date: Wed, 5 Sep 2018 21:01:48 +0530 Subject: [PATCH 79/81] Remove reload_proxy_configuration --- src/helper/site-utils.php | 9 --------- src/site-type/html.php | 4 ++-- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/helper/site-utils.php b/src/helper/site-utils.php index 0d3262e4..b1b02de5 100644 --- a/src/helper/site-utils.php +++ b/src/helper/site-utils.php @@ -205,15 +205,6 @@ function create_site_root( $site_fs_path, $site_url ) { $fs->chown( $site_fs_path, $terminal_username ); } -/** - * Reloads configuration of global-proxy container - * - * @return bool - */ -function reload_proxy_configuration() { - return EE::exec( sprintf( 'docker exec %s sh -c "/app/docker-entrypoint.sh /usr/local/bin/docker-gen /app/nginx.tmpl /etc/nginx/conf.d/default.conf; /usr/sbin/nginx -s reload"', EE_PROXY_TYPE ) ); -} - /** * Adds www to non-www redirection to site * diff --git a/src/site-type/html.php b/src/site-type/html.php index ecd5e731..356a4ddf 100644 --- a/src/site-type/html.php +++ b/src/site-type/html.php @@ -217,12 +217,12 @@ private function create_site() { * when certs are being requested and http+https redirection after we have certs. */ \EE\Site\Utils\add_site_redirects( $this->site_data['site_url'], false, 'inherit' === $this->site_data['site_ssl'] ); - \EE\Site\Utils\reload_proxy_configuration(); + \EE\Site\Utils\reload_global_nginx_proxy(); if ( $this->site_data['site_ssl'] ) { $this->init_ssl( $this->site_data['site_url'], $this->site_data['site_fs_path'], $this->site_data['site_ssl'], $this->site_data['site_ssl_wildcard'] ); \EE\Site\Utils\add_site_redirects( $this->site_data['site_url'], true, 'inherit' === $this->site_data['site_ssl'] ); - \EE\Site\Utils\reload_proxy_configuration(); + \EE\Site\Utils\reload_global_nginx_proxy(); } } catch ( \Exception $e ) { $this->catch_clean( $e ); From bf3fe91e5eaa234e7b39b1a5c02d67001063da23 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Thu, 6 Sep 2018 13:06:49 +0530 Subject: [PATCH 80/81] Convert old args to new for backward compatibility Signed-off-by: Riddhesh Sanghvi --- src/Site_Command.php | 62 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/Site_Command.php b/src/Site_Command.php index fbd95a9b..84d1af8f 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -63,6 +63,7 @@ public static function get_site_types() { public function __invoke( $args, $assoc_args ) { $site_types = self::get_site_types(); + $assoc_args = $this->convert_old_args_to_new_args( $args, $assoc_args ); if ( isset( $assoc_args['type'] ) ) { $type = $assoc_args['type']; @@ -134,4 +135,65 @@ private function determine_type( $args ) { return $type; } + + /** + * Convert EE v3 args to the newer syntax of arguments. + * + * @param array $args Commandline arguments passed. + * @param array $assoc_args Commandline associative arguments passed. + * + * @return array Updated $assoc_args. + */ + private function convert_old_args_to_new_args( $args, $assoc_args ) { + + $ee3_compat_array_map_to_type = [ + 'wp' => [ 'type' => 'wp' ], + 'wpsubdom' => [ 'type' => 'wp', 'mu' => 'subdom' ], + 'wpsubdir' => [ 'type' => 'wp', 'mu' => 'subdir' ], + 'wpredis' => [ 'type' => 'wp', 'cache' => true ], + 'html' => [ 'type' => 'html' ], + 'php' => [ 'type' => 'php' ], + 'mysql' => [ 'type' => 'php', 'with-db' => true ], + 'le' => [ 'ssl' => 'le' ], + 'letsencrypt' => [ 'ssl' => 'le' ], + ]; + + foreach ( $ee3_compat_array_map_to_type as $from => $to ) { + if ( isset( $assoc_args[ $from ] ) ) { + $assoc_args = array_merge( $assoc_args, $to ); + unset( $assoc_args[ $from ] ); + } + } + + // ee3 backward compatibility flags + $wp_compat_array_map = [ + 'user' => 'admin-user', + 'pass' => 'admin-pass', + 'email' => 'admin-email', + ]; + + foreach ( $wp_compat_array_map as $from => $to ) { + if ( isset( $assoc_args[ $from ] ) ) { + $assoc_args[ $to ] = $assoc_args[ $from ]; + unset( $assoc_args[ $from ] ); + } + } + + // backward compatibility error for deprecated flags. + $unsupported_create_old_args = array( + 'w3tc', + 'wpsc', + 'wpfc', + 'pagespeed', + ); + + $old_arg = array_intersect( $unsupported_create_old_args, array_keys( $assoc_args ) ); + + $old_args = implode( ' --', $old_arg ); + if ( isset( $args[1] ) && 'create' === $args[1] && ! empty ( $old_arg ) ) { + \EE::error( "Sorry, --$old_args flag/s is/are no longer supported in EE v4.\nPlease run `ee help " . implode( ' ', $args ) . '`.' ); + } + + return $assoc_args; + } } From 18a2f421a2beedcfbb2efe28cd0a15e125fecc44 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Thu, 6 Sep 2018 13:12:17 +0530 Subject: [PATCH 81/81] Add wp check for wp specific args Signed-off-by: Riddhesh Sanghvi --- src/Site_Command.php | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/Site_Command.php b/src/Site_Command.php index 84d1af8f..14ed148a 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -165,17 +165,20 @@ private function convert_old_args_to_new_args( $args, $assoc_args ) { } } - // ee3 backward compatibility flags - $wp_compat_array_map = [ - 'user' => 'admin-user', - 'pass' => 'admin-pass', - 'email' => 'admin-email', - ]; - - foreach ( $wp_compat_array_map as $from => $to ) { - if ( isset( $assoc_args[ $from ] ) ) { - $assoc_args[ $to ] = $assoc_args[ $from ]; - unset( $assoc_args[ $from ] ); + if ( ! empty( $assoc_args['type'] ) && 'wp' === $assoc_args['type'] ) { + + // ee3 backward compatibility flags + $wp_compat_array_map = [ + 'user' => 'admin-user', + 'pass' => 'admin-pass', + 'email' => 'admin-email', + ]; + + foreach ( $wp_compat_array_map as $from => $to ) { + if ( isset( $assoc_args[ $from ] ) ) { + $assoc_args[ $to ] = $assoc_args[ $from ]; + unset( $assoc_args[ $from ] ); + } } }