commit 8e180f22ea969c1b07b9e004e765222ff7b992bc Author: Denny Cave Date: Thu Oct 5 22:11:32 2023 -0500 Initial commit diff --git a/addon/WPMU.jps b/addon/WPMU.jps new file mode 100755 index 0000000..0cab9d9 --- /dev/null +++ b/addon/WPMU.jps @@ -0,0 +1,45 @@ +jpsType: update +jpsVersion: '1.1' +name: Multisites addon for WordPress cluster +description: Multisites addon for WordPress cluster +logo: https://raw.githubusercontent.com/jelastic-jps/wordpress-cluster/master/images/wp-cluster.png +baseUrl: https://raw.githubusercontent.com/jelastic-jps/wordpress-cluster/master +settings: + main: + fields: + - name: mode + caption: Multisites mode + type: radio-fieldset + values: + subdir: SubDirectories + subdom: SubDomain + default: subdir + +globals: + MODE: ${settings.mode} + +onInstall: + - if (/lemp/.test("${nodes.cp.nodeType}") || /nginxphp/.test("${nodes.cp.nodeType}")): + - if ('${globals.MODE}' == 'subdir'): + cmd[${nodes.cp.master.id}]: |- + wget ${baseUrl}/configs/cp/nginx/subdir.conf -O /etc/nginx/conf.d/SITES_ENABLED/subdir.conf + sudo /etc/init.d/nginx reload + - if ('${globals.MODE}' == 'subdom'): + cmd[${nodes.cp.master.id}]: |- + wget ${baseUrl}/configs/cp/nginx/subdom.conf -O /etc/nginx/conf.d/SITES_ENABLED/subdom.conf + sudo /etc/init.d/nginx reload + + - if (/llsmp/.test("${nodes.cp.nodeType}") || /litespeed/.test("${nodes.cp.nodeType}")): + - if ('${globals.MODE}' == 'subdir'): + cmd[${nodes.cp.master.id}]: |- + wget ${baseUrl}/configs/cp/litespeed/.htaccess_subdir -O /tmp/.htaccess_wpmu + + - if ('${globals.MODE}' == 'subdom'): + cmd[${nodes.cp.master.id}]: |- + wget ${baseUrl}/configs/cp/litespeed/.htaccess_subdom -O /tmp/.htaccess_wpmu + + - cmd[${nodes.cp.master.id}]: |- + cat /tmp/.htaccess_wpmu >> /var/www/webroot/ROOT/.htaccess + wget ${baseUrl}/scripts/setupWP.sh?_r=${fn.random} -O ~/setupWP.sh &>> /var/log/run.log + bash ~/setupWP.sh --wpmu true --MODE ${settings.mode} + diff --git a/addon/myisam2innodb.jps b/addon/myisam2innodb.jps new file mode 100755 index 0000000..edf4fe0 --- /dev/null +++ b/addon/myisam2innodb.jps @@ -0,0 +1,17 @@ +jpsType: update +jpsVersion: '1.1' +id: myisam2innodb +name: WordPress MyISAM to InnoDB converter + +onInstall: + - forEach(nodes.sqldb): + - cmd[${nodes.cp.master.id}]: |- + rm -f /tmp/dump-node${@i.id}.sql + ~/bin/wp config set DB_HOST node${@i.id} --path=${SERVER_WEBROOT} + ~/bin/wp db export /tmp/dump-node${@i.id}.sql --path=${SERVER_WEBROOT} + + - cmd[${nodes.cp.master.id}]: |- + mv $(ls -S /tmp/dump* | head -n 1) /tmp/dump.sql + sed 's/ENGINE=MyISAM/ENGINE=InnoDB/g' /tmp/dump.sql > /tmp/dump-innodb.sql + ~/bin/wp db import /tmp/dump-innodb.sql --path=${SERVER_WEBROOT} + ~/bin/wp config set DB_HOST sqldb --path=${SERVER_WEBROOT} diff --git a/addons/multisite.jps b/addons/multisite.jps new file mode 100755 index 0000000..664b56e --- /dev/null +++ b/addons/multisite.jps @@ -0,0 +1,44 @@ +jpsType: update +jpsVersion: '1.1' +id: wordpress-multisite +name: WordPress Multisite +description: WordPress Multisite +logo: https://raw.githubusercontent.com/jelastic-jps/wordpress-cluster/master/images/wp-cluster.png + +settings: + fields: + - name: mode + caption: Multisites mode + type: radio-fieldset + values: + subdir: SubDirectories + subdom: SubDomain + default: subdir + +globals: + mode: ${settings.mode:subdir} + +onInstall: + - if (/lemp/.test("${nodes.cp.nodeType}") || /nginxphp/.test("${nodes.cp.nodeType}")): + - if ('${globals.mode}' == 'subdir'): + cmd[${nodes.cp.master.id}]: |- + wget ${baseUrl}../configs/cp/nginx/subdir.conf -O /etc/nginx/conf.d/sites-enabled/subdir.conf; + sudo jem service restart + - if ('${globals.mode}' == 'subdom'): + cmd[${nodes.cp.master.id}]: |- + wget ${baseUrl}../configs/cp/nginx/subdom.conf -O /etc/nginx/conf.d/sites-enabled/subdom.conf; + sudo jem service restart + + - if (/llsmp/.test("${nodes.cp.nodeType}") || /litespeed/.test("${nodes.cp.nodeType}")): + - if ('${globals.mode}' == 'subdir'): + cmd[${nodes.cp.master.id}]: |- + wget ${baseUrl}../configs/cp/litespeed/.htaccess_subdir -O /tmp/.htaccess_wpmu; + + - if ('${globals.mode}' == 'subdom'): + cmd[${nodes.cp.master.id}]: |- + wget ${baseUrl}../configs/cp/litespeed/.htaccess_subdom -O /tmp/.htaccess_wpmu; + + - cmd[${nodes.cp.master.id}]: |- + cat /tmp/.htaccess_wpmu >> /var/www/webroot/ROOT/.htaccess; + bash ~/bin/setupWP.sh --multisite true --mode ${globals.mode}; + diff --git a/configs/autotest.yaml b/configs/autotest.yaml new file mode 100755 index 0000000..5632edd --- /dev/null +++ b/configs/autotest.yaml @@ -0,0 +1,42 @@ +jps: https://github.com/jelastic-jps/wordpress-cluster/blob/v2.0.0/manifest.yml +component: wordpress +stack: + - nodeType: litespeedadc + tagSetting: bl_tag + nodeGroup: bl + optimization: true + options: + - ls-addon: true + wp_protect: true + waf: true + - nodeType: litespeedphp + tagSetting: cp_tag + nodeGroup: cp + optimization: true + options: + - ls-addon: true + wp_protect: true + waf: true + - nodeType: nginx + tagSetting: bl_tag + nodeGroup: bl + options: + - ls-addon: false + - nodeType: nginxphp + tagSetting: cp_tag + nodeGroup: cp + optimization: true + options: + - ls-addon: false + - nodeType: mariadb + tagSetting: sqldb_tag + nodeGroup: sqldb + options: + - galera: true + - galera: false + - nodeType: storage + tagSetting: storage_tag + nodeGroup: storage + options: + - glusterfs: false + - glusterfs: true diff --git a/configs/lb/litespeed/jelastic.xml b/configs/lb/litespeed/jelastic.xml new file mode 100755 index 0000000..51d578b --- /dev/null +++ b/configs/lb/litespeed/jelastic.xml @@ -0,0 +1,23 @@ + + + + + 1 + + + + 0 + 10 + + + + /tmp/lscache/vhosts/$VH_NAME + 0 + + + 1 + 1 + 15 + + + diff --git a/configs/settings.yaml b/configs/settings.yaml new file mode 100755 index 0000000..0e49fe1 --- /dev/null +++ b/configs/settings.yaml @@ -0,0 +1,25 @@ +fields: +- caption: Scaling Strategy + type: list + name: loadGrowth + default: slow + required: true + width: 225 + tooltip: | + Configure auto-scaling triggers, i.e. how fast the system responds to load spikes by adding or removing nodes. +

Read more about Automatic Horizontal Scaling

+ values: + - value: slow + caption: Low Load + tooltip:

Low load scaling strategy

add 1 new node when CPU > 70%

remove when CPU < 20%

+ - value: medium + caption: Medium Load + tooltip:

Medium load scaling strategy

add 1 new node when CPU > 50%

remove when CPU < 20%

+ - value: fast + caption: High Load + tooltip:

High load scaling strategy

add 2 new nodes when CPU > 30%

remove when CPU < 10%

+ +- caption: Advanced Features + type: displayfield + name: displayfield + markup: diff --git a/configs/sqldb/wordpress.cnf b/configs/sqldb/wordpress.cnf new file mode 100755 index 0000000..d4fbb10 --- /dev/null +++ b/configs/sqldb/wordpress.cnf @@ -0,0 +1,16 @@ +[mysqld] + +# Duplicate entry '_transient_doing_cron' for key 'option_name', Error_code: 1062; +slave-skip-errors = 1062 + +max_connections=500 +join_buffer_size = 3M +tmp_table_size = 128M +max_heap_table_size = 128M +thread_cache_size = 16K +table_definition_cache = 4K +open_files_limit = 524290 +local-infile=0 +innodb_log_file_size = 128M +wsrep_slave_threads = 16 +innodb_flush_log_at_trx_commit = 2 diff --git a/configs/wordpress/wp-jelastic.php b/configs/wordpress/wp-jelastic.php new file mode 100755 index 0000000..27ac7e1 --- /dev/null +++ b/configs/wordpress/wp-jelastic.php @@ -0,0 +1,9 @@ +Cluster diff --git a/images/cluster.svg b/images/cluster.svg new file mode 100755 index 0000000..2b4d5b6 --- /dev/null +++ b/images/cluster.svg @@ -0,0 +1 @@ +geo clusters diff --git a/images/deploy-to-jelastic.png b/images/deploy-to-jelastic.png new file mode 100755 index 0000000..8395aef Binary files /dev/null and b/images/deploy-to-jelastic.png differ diff --git a/images/favicon.ico b/images/favicon.ico new file mode 100755 index 0000000..367f011 Binary files /dev/null and b/images/favicon.ico differ diff --git a/images/install-new.png b/images/install-new.png new file mode 100755 index 0000000..6736ce2 Binary files /dev/null and b/images/install-new.png differ diff --git a/images/install-v2.png b/images/install-v2.png new file mode 100755 index 0000000..8c1e3e5 Binary files /dev/null and b/images/install-v2.png differ diff --git a/images/single-cluster-topology-storage-scaling-v2.png b/images/single-cluster-topology-storage-scaling-v2.png new file mode 100755 index 0000000..1b6bed3 Binary files /dev/null and b/images/single-cluster-topology-storage-scaling-v2.png differ diff --git a/images/single-cluster-topology-storage-scaling.png b/images/single-cluster-topology-storage-scaling.png new file mode 100755 index 0000000..774619b Binary files /dev/null and b/images/single-cluster-topology-storage-scaling.png differ diff --git a/images/single-cluster-topology.png b/images/single-cluster-topology.png new file mode 100755 index 0000000..86b0a66 Binary files /dev/null and b/images/single-cluster-topology.png differ diff --git a/images/standalone.svg b/images/standalone.svg new file mode 100755 index 0000000..25b7201 --- /dev/null +++ b/images/standalone.svg @@ -0,0 +1 @@ +geo clusters_1 diff --git a/images/success-wordpress.png b/images/success-wordpress.png new file mode 100755 index 0000000..16c61cf Binary files /dev/null and b/images/success-wordpress.png differ diff --git a/images/woo_logo.png b/images/woo_logo.png new file mode 100755 index 0000000..5e884f7 Binary files /dev/null and b/images/woo_logo.png differ diff --git a/images/wordpress-multisite.png b/images/wordpress-multisite.png new file mode 100755 index 0000000..aad89b0 Binary files /dev/null and b/images/wordpress-multisite.png differ diff --git a/images/wp-cluster-business.png b/images/wp-cluster-business.png new file mode 100755 index 0000000..b6650e9 Binary files /dev/null and b/images/wp-cluster-business.png differ diff --git a/images/wp-cluster-enterprise.png b/images/wp-cluster-enterprise.png new file mode 100755 index 0000000..7976bfe Binary files /dev/null and b/images/wp-cluster-enterprise.png differ diff --git a/images/wp-cluster-installation.png b/images/wp-cluster-installation.png new file mode 100755 index 0000000..23ac534 Binary files /dev/null and b/images/wp-cluster-installation.png differ diff --git a/images/wp-cluster-installed.png b/images/wp-cluster-installed.png new file mode 100755 index 0000000..3816588 Binary files /dev/null and b/images/wp-cluster-installed.png differ diff --git a/images/wp-cluster-kit.png b/images/wp-cluster-kit.png new file mode 100755 index 0000000..fe390d9 Binary files /dev/null and b/images/wp-cluster-kit.png differ diff --git a/images/wp-cluster-kit.svg b/images/wp-cluster-kit.svg new file mode 100755 index 0000000..62d88bd --- /dev/null +++ b/images/wp-cluster-kit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/wp-cluster.png b/images/wp-cluster.png new file mode 100755 index 0000000..28829ca Binary files /dev/null and b/images/wp-cluster.png differ diff --git a/images/wp-standalone-pro.png b/images/wp-standalone-pro.png new file mode 100755 index 0000000..4bf71ce Binary files /dev/null and b/images/wp-standalone-pro.png differ diff --git a/images/wp-standalone-starter.png b/images/wp-standalone-starter.png new file mode 100755 index 0000000..4ea38cc Binary files /dev/null and b/images/wp-standalone-starter.png differ diff --git a/images/wp_logo.svg b/images/wp_logo.svg new file mode 100755 index 0000000..ff62eb1 --- /dev/null +++ b/images/wp_logo.svg @@ -0,0 +1 @@ +WP_logo \ No newline at end of file diff --git a/images/wp_logo_70.png b/images/wp_logo_70.png new file mode 100755 index 0000000..af0f7b0 Binary files /dev/null and b/images/wp_logo_70.png differ diff --git a/manifest.yml b/manifest.yml new file mode 100755 index 0000000..8ff03fb --- /dev/null +++ b/manifest.yml @@ -0,0 +1,220 @@ +type: install +jpsVersion: '1.7.2' +name: WordPress Performance Cluster +id: wp-performance-cluster +categories: + - apps/clusters + - apps/content-management +description: + #text: WordPress Cluster Kit with highly available Load Balancer and Shared Storage with GlusterFS, database clustering, and scaling mode to create an optimal environment for highly-loaded projects. The package provides integrated autoscaling and high availability for development and production environments. Clustered topology ensures effective handling of heavy workload. + #short: WordPress Cluster with built-in kit v2 for choosing optimal servers, database clustering type, scaling mode and a set of advanced features for highly-loaded projects +logo: /images/wp-cluster-kit.svg + +baseUrl: https://raw.githubusercontent.com/jelastic-jps/wordpress-cluster/v2.2.0 + +onBeforeInit: /scripts/beforeInit.js?_r=${fn.random} +onBeforeInstall: /scripts/beforeInstall.js?_r=${fn.random} + +skipNodeEmails: true +nodes: definedInOnBeforeInstall + +settings: + fields: + + # - caption: Number of App servers + # - caption: Scalable app servers limit + # - caption: App server base vCPU + # - caption: App server scalable vCPU + # - caption: PHP Version + + # - caption: Email credentials + # type: checkbox + # name: ls-addon + # value: true + # disabled: false + # tooltip: "If this option is enabled, environment details (including WP admin logins) will be emailed to you upon successful deployment." + + # - caption: Database type (single or clustered) + # relay & OCP + # s3 offloading + +mixins: + - /scripts/common.yml + +globals: + PATH: ${baseUrl} + DB_USER: ${settings.DB_USER:user-[fn.random]} + DB_PASS: ${settings.DB_PASS:[fn.password(10)]} + DB_HOST: sqldb + PROTOCOL: https + WP_ADMIN_PASS: ${settings.WP_ADMIN_PASS:[fn.password(10)]} + LS_ADMIN_PASS: ${settings.LS_ADMIN_PASS:[fn.password(10)]} + +onInstall: + - addLimits + #- addMetadata + - setDomain # why is this necessary? + - initLEsettings + #- if (${settings.is_trigger:true}): setTriggers + - optimization + - setupCacheSync + - storageHealthCheck + - storageMount: NFS4 + - setPassword + - getRedisPswd + - installWordpress + #- if ('${settings.mu-addon:false}' == 'true'): configureMultisite + + - script: | + var actions = []; + actions.push({ + jps: "https://github.com/jelastic-jps/lets-encrypt/blob/master/manifest.jps?_r=${fn.random}", + nodeGroup: "bl", + skipEmail: "true", + settings: { + customDomains: "${globals.DOMAIN}", + fallbackToX1: "true", + withExtIp: "${globals.isExtIP}" + } + }); + return { result: 0, onAfterReturn: { install: actions } }; + + - setupLEdomain + + - install: + - jps: /scripts/cacheClean.jps?_r=${fn.random} + - jps: /scripts/addons.jps?_r=${fn.random} + - jps: /scripts/events.jps?_r=${fn.random} + + #instant login, root access, and other addons + + - return: + type: success + message: /success/text/success.md?_r=${fn.random} + email: /success/email/success.md?_r=${fn.random} + +actions: + + addLimits: #what does this do? + - env.control.ApplyNodeGroupData [*]: + data: + isRequired: true + + # addMetadata: + # script: | + # var metadata = { project: "${settings.project:default}", projectScope: "${settings.projectScope:production}" }; + # return api.env.control.ApplyEnvProperty ? + # api.env.control.ApplyEnvProperty('${env.name}', session, metadata) : + # api.env.control.ApplyNodeGroupData('${env.name}', session, 'cp', metadata); + + setDomain: + - script: /scripts/idna.js + domains: ${env.domain} + - setGlobals: + DOMAIN: ${response.domains} + + # setTriggers: + # - log: Auto Scaling Triggers + # - script: /scripts/addTriggers.js + # nodeGroup: cp + # resourceType: CPU + # loadGrowth: 'slow' + # cleanOldTriggers: true + # scaleDownLimit: ${nodes.cp.length} + + initLEsettings: + # I don't think we need to check this. Just set to true. + # - script: | + # return { + # result:0, + # extIP: Boolean(jelastic.billing.account.GetQuotas('environment.externalip.enabled').array[0].value) + # } + # - setGlobals: + # isExtIP: ${response.extIP} + + - setGlobals: + isExtIP: true + + - cmd[cp, bl]: |- + [ ! -d /var/lib/jelastic/keys/letsencrypt ] && mkdir -p /var/lib/jelastic/keys/letsencrypt; + echo "webroot=false" > /var/lib/jelastic/keys/letsencrypt/settings-custom; + echo "webrootPath=/var/www/webroot/ROOT" >> /var/lib/jelastic/keys/letsencrypt/settings-custom; + echo "test=false" >> /var/lib/jelastic/keys/letsencrypt/settings-custom; + echo "withExtIp=${globals.isExtIP}" >> /var/lib/jelastic/keys/letsencrypt/settings-custom; + user: root + + setupLEdomain: + - cmd[${nodes.bl.master.id}]: source /opt/letsencrypt/settings && echo $domain + - cmd[${nodes.cp.master.id}]: bash ~/bin/setupWP.sh --url https://${response.out}; + + optimization: + - log: Load Balancers and App servers optimization + - install: + - jps: https://raw.githubusercontent.com/jelastic/templates/master/config_v2.jps?_r=${fn.random} + settings: + targetGroup: bl + targetNodes: bl + optimization: wordpress + - jps: https://raw.githubusercontent.com/jelastic/templates/master/config_v2.jps?_r=${fn.random} + settings: + targetGroup: cp + targetNodes: cp + optimization: wordpress + - cmd[cp, bl]: if test -f /usr/local/sbin/optimization.sh; then bash /usr/local/sbin/optimization.sh &>> /var/log/run.log; fi + + setPassword: + - cmd[cp, bl]: jem passwd set -p ${globals.LS_ADMIN_PASS} + user: root + + storageMount: + - log: Mount Storage + - api: + - method: jelastic.environment.file.AddMountPointByGroup + params: + nodeGroup: cp + sourceNodeId: ${nodes.storage.master.id} + sourcePath: /data + path: /var/www/webroot/ROOT + sourceAddressType: NODE_GROUP + protocol: ${this} + + storageHealthCheck: + - cmd[cp]: |- + echo "" > /var/www/webroot/ROOT/index.php + + #configureMultisite: + # - install: /addons/multisite.jps + + getRedisPswd: + - cmd[nosqldb]: cat /etc/redis.conf | tail -1 | awk '{print $2}'; + - setGlobals: + REDIS_PSWD: ${response.out} + + installWordpress: + - install: /scripts/installWP.jps + settings: + db_host: ${globals.DB_HOST} + db_user: ${globals.DB_USER} + db_pass: ${globals.DB_PASS} + redis_host: nosqldb + redis_port: 6379 + redis_user: admin + redis_pswd: ${globals.REDIS_PSWD} + wp_admin_pass: ${globals.WP_ADMIN_PASS} + wp_title: "Hello World" + wp_url: ${globals.PROTOCOL}://${globals.DOMAIN}/ + version_wordpress: ${globals.version_wordpress} + + setupCacheSync: + - if (/litespeed/.test("${nodes.bl.nodeType}")): + - install: /scripts/setupHA4LB.jps?_r=${fn.random} + + updateTriggers: + if (!${event.params.auto:true}): + - log: update scaling trigger + - script: /scripts/updateTriggers.js + count: ${nodes.cp.length} + +# other stuff - basic BB optimizations should be applied here +# use WP redis cache plugin instead of litespeed redis cache +# Use https://plugintests.com/plugins/wporg/litespeed-cache/tips to disable ls cache page? \ No newline at end of file diff --git a/scripts/addTriggers.js b/scripts/addTriggers.js new file mode 100755 index 0000000..bba2fc1 --- /dev/null +++ b/scripts/addTriggers.js @@ -0,0 +1,92 @@ +//@auth +//@req(nodeGroup, resourceType, cleanOldTriggers, loadGrowth) + +var scaleUpLoadPeriod = 1, + scaleDownLimit = getParam("scaleDownLimit") || 2, + scaleDownLoadPeriod = 5; + +var resp = jelastic.billing.account.GetQuotas('environment.maxsamenodescount'); +if (resp.result != 0) return resp; +var scaleUpLimit = resp.array[0] && resp.array[0].value ? resp.array[0].value : 1000; + +if (scaleUpLimit <= scaleDownLimit) return {result:0, warning: 'autoscaling triggers have not been added due to upLimit ['+scaleUpLimit+'] <= downLimit ['+scaleDownLimit+']'} + +if (loadGrowth.toLowerCase() == "slow") { + var scaleUpValue = 70, + scaleDownValue = 20, + scaleNodeCount = 1; +} + +if (loadGrowth.toLowerCase() == "medium") { + var scaleUpValue = 50, + scaleDownValue = 20, + scaleNodeCount = 1; +} + +if (loadGrowth.toLowerCase() == "fast") { + var scaleUpValue = 30, + scaleDownValue = 10, + scaleNodeCount = 2; +} + +if (cleanOldTriggers) { + var actions = ['ADD_NODE', 'REMOVE_NODE']; + for (var i = 0; i < actions.length; i++){ + var array = jelastic.env.trigger.GetTriggers(appid, session, actions[i]).array; + for (var j = 0; j < array.length; j++) jelastic.env.trigger.DeleteTrigger(appid, session, array[j].id); + } +} + +resp = jelastic.env.trigger.AddTrigger('${env.envName}', session, + { + "isEnabled": true, + "name": "scale-up", + "nodeGroup": nodeGroup, + "period": scaleUpLoadPeriod, + "condition": { + "type": "GREATER", + "value": scaleUpValue, + "resourceType": resourceType, + "valueType": "PERCENTAGES" + }, + "actions": [ + { + "type": "ADD_NODE", + "customData": { + "limit": scaleUpLimit, + "count": scaleNodeCount, + "notify": true + } + } + ] + } +); + +if (resp.result != 0) return resp; + +resp = jelastic.env.trigger.AddTrigger('${env.envName}', session, + { + "isEnabled": true, + "name": "scale-down", + "nodeGroup": nodeGroup, + "period": scaleDownLoadPeriod, + "condition": { + "type": "LESS", + "value": scaleDownValue, + "resourceType": resourceType, + "valueType": "PERCENTAGES" + }, + "actions": [ + { + "type": "REMOVE_NODE", + "customData": { + "limit": scaleDownLimit, + "count": 1, + "notify": true + } + } + ] + } +); + +return resp; diff --git a/scripts/addons.jps b/scripts/addons.jps new file mode 100755 index 0000000..df5e506 --- /dev/null +++ b/scripts/addons.jps @@ -0,0 +1,73 @@ +type: update +id: wordpress-addons +name: Addons for WordPress +description: Addons for WordPress + +onAfterClone: + - script: delete MANIFEST.id; return {result:0, jps:MANIFEST}; + - install [cp]: ${response.jps} + envName: ${event.response.env.envName} + +onInstall: + installAddon: + - id: setup-site-url-addon + nodeGroup: cp + - id: cache-purge-addon + nodeGroup: cp + +addons: + - id: setup-site-url-addon + type: update + name: WordPress Site Address (URL) + description: The Site Address(URL) setting is the address you want people to type in their browser to reach your WordPress blog. + logo: https://github.com/jelastic-jps/wordpress/blob/master/wordpress-edition/images/logo/cluster.svg + settings: + fields: + - type: string + name: siteURL + caption: Site Address (URL) + default: '' + required: true + regex: "^https?:\\/\\/.+$" + regexText: Incorrect Site URL. + + buttons: + - caption: Site URL + settings: main + action: setup_site_url + loadingText: Applying... + confirmText: Do you want to change Site URL? + successText: Site URL for WordPress has been successfully applyed! + + - id: cache-purge-addon + type: update + name: Cache Manager + description: Clean all caches at once. Object Cache, Static Cache... + logo: https://github.com/jelastic-jps/wordpress/blob/master/wordpress-edition/images/logo/cluster.svg + + buttons: + - caption: Clean all caches + action: cache_purge + loadingText: Cleaning... + confirmText: Do you want to clean all caches? + successText: Caches have been successfully cleaned! + +actions: + litespeed-cache-clean: + - if (nodes.bl): + cmd[bl]: |- + [ -d /tmp/lscache/vhosts/Jelastic/ ] && rm -rf /tmp/lscache/vhosts/Jelastic/* &>> /var/log/run.log; + - cmd[cp]: |- + [ -d /var/www/webroot/.cache/vhosts/Jelastic/ ] && rm -rf /var/www/webroot/.cache/vhosts/Jelastic/* &>> /var/log/run.log; + + wordpress-cache-clean: + - cmd[cp]: |- + wp cache flush --path=/var/www/webroot/ROOT/ &>> /var/log/run.log; + + cache_purge: + - if (/llsmp/.test("${nodes.cp.nodeType}") || /litespeed/.test("${nodes.cp.nodeType}")): litespeed-cache-clean + - wordpress-cache-clean + + setup_site_url: + - cmd[${nodes.cp.master.id}]: bash ~/bin/setupWP.sh --url ${settings.siteURL} + - cache_purge \ No newline at end of file diff --git a/scripts/balancerRebuild.jps b/scripts/balancerRebuild.jps new file mode 100755 index 0000000..46cea73 --- /dev/null +++ b/scripts/balancerRebuild.jps @@ -0,0 +1,14 @@ +jpsType: update +name: Balancer Rebuild +description: This script for balancer rebuild +id: wordpress-balancer-rebuild + +onInstall: + - cmd[bl]: |- + [ -f /var/www/conf/hosts_list ] && rm -f /var/www/conf/hosts_list; + - forEach(i:nodes.cp): + cmd[bl]: echo '${@i.address}' >> /var/www/conf/hosts_list; + - cmd[bl]: |- + jem balancer clear; + jem balancer rebuildCommon; + user: root diff --git a/scripts/beforeInit.js b/scripts/beforeInit.js new file mode 100755 index 0000000..e91237f --- /dev/null +++ b/scripts/beforeInit.js @@ -0,0 +1,151 @@ +import com.hivext.api.Response; +import org.yaml.snakeyaml.Yaml; +import com.hivext.api.core.utils.Transport; + +var cdnAppid = "c05ffa5b45628a2a0c95467ebca8a0b4"; +var lsAppid = "9e6afcf310004ac84060f90ff41a5aba"; +var group = jelastic.billing.account.GetAccount(appid, session); +var isCDN = jelastic.dev.apps.GetApp(cdnAppid); +var isLS = jelastic.dev.apps.GetApp(lsAppid); + +//checking quotas +var perEnv = "environment.maxnodescount", + maxEnvs = "environment.maxcount", + perNodeGroup = "environment.maxsamenodescount", + maxCloudletsPerRec = "environment.maxcloudletsperrec"; +var nodesPerEnvWO_Bl = 9, + nodesPerEnvWO_GlusterFS = 7, + nodesPerEnvMin = 6, + nodesPerGroupMin = 2, + maxCloudlets = 16, + markup = "", cur = null, text = "used", prod = true; + +var settings = jps.settings; +var fields = {}; +for (var i = 0, field; field = jps.settings.fields[i]; i++) + fields[field.name] = field; + +var quotas = jelastic.billing.account.GetQuotas(perEnv + ";"+maxEnvs+";" + perNodeGroup + ";" + maxCloudletsPerRec ).array; +var group = jelastic.billing.account.GetAccount(appid, session); +for (var i = 0; i < quotas.length; i++){ + var q = quotas[i], n = toNative(q.quota.name); + + if (n == maxCloudletsPerRec && maxCloudlets > q.value){ + err(q, "required", maxCloudlets, true); + prod = false; + } + + if (n == perEnv && nodesPerEnvMin > q.value){ + if (!markup) err(q, "required", nodesPerEnvMin, true); + prod = false; + } + + if (n == perNodeGroup && nodesPerGroupMin > q.value){ + if (!markup) err(q, "required", nodesPerGroupMin, true); + prod = false; + } + + if (n == perEnv && nodesPerEnvMin == q.value){ + fields["glusterfs"].value = false; + fields["glusterfs"].disabled = true; + fields["galera"].value = false; + fields["galera"].disabled = true; + fields["bl_count"].value = 1; + fields["displayfield"].markup = "Some advanced features are not available. Please upgrade your account."; + fields["displayfield"].cls = "warning"; + fields["displayfield"].hideLabel = true; + fields["displayfield"].height = 25; + } + + if (n == perEnv && nodesPerEnvWO_GlusterFS == q.value){ + fields["glusterfs"].value = false; + fields["glusterfs"].disabled = true; + fields["bl_count"].value = 1; + fields["displayfield"].markup = "Some advanced features are not available. Please upgrade your account."; + fields["displayfield"].cls = "warning"; + fields["displayfield"].hideLabel = true; + fields["displayfield"].height = 25; + } + + if (n == perEnv && q.value == 8){ + fields["glusterfs"].value = false; + fields["glusterfs"].disabled = true; + fields["bl_count"].value = 2; + fields["displayfield"].markup = "Some advanced features are not available. Please upgrade your account."; + fields["displayfield"].cls = "warning"; + fields["displayfield"].hideLabel = true; + fields["displayfield"].height = 25; + } + + if (n == perEnv && nodesPerEnvWO_Bl == q.value){ + fields["bl_count"].value = 1; + } + + if (n == perNodeGroup && nodesPerGroupMin == q.value){ + fields["glusterfs"].value = false; + fields["glusterfs"].disabled = true; + fields["galera"].value = false; + fields["galera"].disabled = true; + fields["displayfield"].markup = "Some advanced features are not available. Please upgrade your account."; + fields["displayfield"].cls = "warning"; + fields["displayfield"].hideLabel = true; + fields["displayfield"].height = 25; + } + + if (isLS.result == 0 || isLS.result == Response.PERMISSION_DENIED) { + fields["ls-addon"].hidden = false; + fields["ls-addon"].value = true; + } else { + fields["ls-addon"].hidden = true; + fields["ls-addon"].value = false; + fields["ls-addon"].showIf = null; + } + + if (isCDN.result == 0 || isCDN.result == Response.PERMISSION_DENIED) { + fields["cdn-addon"].hidden = false; + fields["cdn-addon"].value = true; + } else { + fields["cdn-addon"].hidden = true; + fields["cdn-addon"].value = false; + } +} + +if (!prod || group.groupType == 'trial') { + fields["ls-addon"].disabled = true; + fields["ls-addon"].value = false; + fields["loadGrowth"].disabled = true; + fields["galera"].disabled = true; + fields["galera"].value = false; + fields["glusterfs"].disabled = true; + fields["glusterfs"].value = false; + fields["le-addon"].disabled = true; + fields["le-addon"].value = false; + fields["cdn-addon"].disabled = true; + fields["cdn-addon"].value = false; + fields["mu-addon"].disabled = true; + fields["displayfield"].markup = "Advanced features are not available."; + fields["displayfield"].cls = "warning"; + fields["displayfield"].hideLabel = true; + fields["displayfield"].height = 25; + fields["bl_count"].markup = "WordPress cluster is not available. " + markup + "Please upgrade your account."; + if (group.groupType == 'trial') + fields["bl_count"].markup = "WordPress cluster is not available for " + group.groupType + ". Please upgrade your account."; + fields["bl_count"].cls = "warning"; + fields["bl_count"].hidden = false; + fields["bl_count"].height = 30; + + + settings.fields.push( + {"type": "compositefield","height": 0,"hideLabel": true,"width": 0,"items": [{"height": 0,"type": "string","required": true}]} + ); +} + +return { + result: 0, + settings: settings +}; + +function err(e, text, cur, override){ + var m = (e.quota.description || e.quota.name) + " - " + e.value + ", " + text + " - " + cur + ". "; + if (override) markup = m; else markup += m; +} diff --git a/scripts/beforeInstall.js b/scripts/beforeInstall.js new file mode 100755 index 0000000..e979e0b --- /dev/null +++ b/scripts/beforeInstall.js @@ -0,0 +1,91 @@ +var wpbfp = "THROTTLE"; +var db_cluster = 'single'; //not sure if 'single' will work. If not, then try 'slave' or 'master' +var db_count = 1; //or 2 if 'slave' or 'master' db_cluster scheme +var nfs_protocol = "NFS4"; + +var resp = { + result: 0, + ssl: !!jelastic.billing.account.GetQuotas('environment.jelasticssl.enabled').array[0].value, + nodes: [] +} + +resp.nodes.push({ + nodeType: "storage", + count: 1, + cloudlets: ${settings.storage.cloudlets:8}, + diskLimit: "${settings.storage.diskspace:[quota.disk.limitation]}", + nodeGroup: "storage", + validation: { + minCount: 1, + maxCount: 1 + } +}); + + +// https://docs.cloudscripting.com/creating-manifest/basic-configs/#cluster-parameter + +resp.nodes.push({ + nodeType: "mariadb-dockerized", + cloudlets: ${settings.sqldb.cloudlets:16}, + diskLimit: "${settings.sqldb.diskspace:[quota.disk.limitation]}", + count: db_count, + nodeGroup: "sqldb", + restartDelay: 10, + skipNodeEmails: true, + validation: { + minCount: db_count, + maxCount: db_count + }, + cluster: { + scheme: db_cluster, + db_user: "${globals.DB_USER}", + db_pass: "${globals.DB_PASS}", + is_proxysql: false, + custom_conf: "${baseUrl}/configs/sqldb/wordpress.cnf" + }, + env: { + SCHEME: db_cluster, + DB_USER: "${globals.DB_USER}", + DB_PASS: "${globals.DB_PASS}", + IS_PROXYSQL: false + } +}); + +resp.nodes.push({ + nodeType: "litespeedadc", + count: 1, + cloudlets: ${settings.bl.cloudlets:8}, + diskLimit: "${settings.bl.diskspace:[quota.disk.limitation]}", + nodeGroup: "bl", + restartDelay: 10, + env: { + WP_PROTECT: wpbfp, + WP_PROTECT_LIMIT: 100 + } +}, { + nodeType: "litespeedphp", + count: ${settings.cp.nodes:2}, + cloudlets: ${settings.cp.cloudlets:8}, + diskLimit: "${settings.cp.diskspace:[quota.disk.limitation]}", + nodeGroup: "cp", + restartDelay: 10, + env: { + SERVER_WEBROOT: "/var/www/webroot/ROOT", + REDIS_ENABLED: "true", + WAF: "${settings.waf:false}", + WP_PROTECT: "OFF" + }, + volumes: [ + "/var/www/webroot/ROOT" + ] +}); + +resp.nodes.push({ + nodeType: "redis", + count: 1, + cloudlets: ${settings.nosqldb.cloudlets:8}, + diskLimit: "${settings.nosqldb.diskspace:[quota.disk.limitation]}", + nodeGroup: "nosqldb" +}); + +return resp; diff --git a/scripts/cacheClean.jps b/scripts/cacheClean.jps new file mode 100755 index 0000000..e1b955d --- /dev/null +++ b/scripts/cacheClean.jps @@ -0,0 +1,18 @@ +jpsType: update +name: Cache Clean +description: This script for cache clean +id: wordpress-cache-clean + +onInstall: + - if (/llsmp/.test("${nodes.cp.nodeType}") || /litespeed/.test("${nodes.cp.nodeType}")): litespeed-cache-clean + - wordpress-cache-clean + +actions: + litespeed-cache-clean: + - if (nodes.bl): + cmd[bl]: |- + [ -d /tmp/lscache/vhosts/Jelastic/ ] && rm -rf /tmp/lscache/vhosts/Jelastic/* &>> /var/log/run.log; + + wordpress-cache-clean: + - cmd[cp]: |- + wp cache flush --path=/var/www/webroot/ROOT &>> /var/log/run.log; diff --git a/scripts/common.yml b/scripts/common.yml new file mode 100755 index 0000000..647af13 --- /dev/null +++ b/scripts/common.yml @@ -0,0 +1,97 @@ +actions: + applyEnvSettings: + script: | + var envs = '${this.targetAppid}'.split(','); + let nodes = []; + let nodeGroups = [], node, nodesByGroup, cloudlets, diskspace, count; + + function getNodesByGroup(targetAppid, group) { + let groupNodes = []; + let resp = jelastic.env.control.GetEnvInfo(targetAppid, session); + if (resp.result != 0) return resp; + let nodes = resp.nodes; + for (let i = 0, n = nodes.length; i < n; i++) { + if (nodes[i].nodeGroup == group) { + groupNodes.push(nodes[i]); + } + } + return { result: 0, nodes: groupNodes } + }; + + for (var i=0, n = envs.length; i < n; i++) { + let targetAppid = envs[i]; + let resp = jelastic.env.control.GetEnvInfo(targetAppid, session); + if (resp.result != 0) return resp; + + var env = resp.env; + + for (let i = 0, n = resp.nodes.length; i < n; i++) { + node = resp.nodes[i]; + + if (nodeGroups.indexOf(String(node.nodeGroup)) == -1) { + nodeGroups.push(String(node.nodeGroup)); + + nodesByGroup = getNodesByGroup(targetAppid, node.nodeGroup); + if (nodesByGroup.result != 0) return nodesByGroup; + + cloudlets = node.flexibleCloudlets; + diskspace = node.diskLimit / 1000; + count = nodesByGroup.nodes.length; + + if (node.nodeGroup == 'bl') { + if (!/cloudlets/.test('${this.bl.cloudlets}')) + cloudlets = String(node.flexibleCloudlets) != '${this.bl.cloudlets}' ? '${this.bl.cloudlets}' : node.flexibleCloudlets; + if (!/diskspace/.test('${this.bl.diskspace}')) + diskspace = String(diskspace) != '${this.bl.diskspace}' ? '${this.bl.diskspace}' : diskspace; + if (!/nodes/.test('${this.bl.nodes}')) + count = String(nodesByGroup.nodes.length) != '${this.bl.nodes}' ? '${this.bl.nodes}' : nodesByGroup.nodes.length; + } + + if (node.nodeGroup == 'cp') { + if (!/cloudlets/.test('${this.cp.cloudlets}')) + cloudlets = String(node.flexibleCloudlets) != '${this.cp.cloudlets}' ? '${this.cp.cloudlets}' : node.flexibleCloudlets; + if (!/diskspace/.test('${this.cp.diskspace}')) + diskspace = String(node.diskLimit) != '${this.cp.diskspace}' ? '${this.cp.diskspace}' : node.diskLimit; + if (!/nodes/.test('${this.cp.nodes}')) + count = String(nodesByGroup.nodes.length) != '${this.cp.nodes}' ? '${this.cp.nodes}' : nodesByGroup.nodes.length; + } + + if (node.nodeGroup == 'sqldb') { + if (!/cloudlets/.test('${this.sqldb.cloudlets}')) + cloudlets = String(node.flexibleCloudlets) != '${this.sqldb.cloudlets}' ? '${this.sqldb.cloudlets}' : node.flexibleCloudlets; + if (!/diskspace/.test('${this.sqldb.diskspace}')) + diskspace = String(node.diskLimit) != '${this.sqldb.diskspace}' ? '${this.sqldb.diskspace}' : node.diskLimit; + } + + if (node.nodeGroup == 'nosqldb') { + if (!/cloudlets/.test('${this.nosqldb.cloudlets}')) + cloudlets = String(node.flexibleCloudlets) != '${this.nosqldb.cloudlets}' ? '${this.nosqldb.cloudlets}' : node.flexibleCloudlets; + if (!/diskspace/.test('${this.nosqldb.diskspace}')) + diskspace = String(node.diskLimit) != '${this.nosqldb.diskspace}' ? '${this.nosqldb.diskspace}' : node.diskLimit; + } + + if (node.nodeGroup == 'storage') { + if (!/cloudlets/.test('${this.storage.cloudlets}')) + cloudlets = String(node.flexibleCloudlets) != '${this.storage.cloudlets}' ? '${this.storage.cloudlets}' : node.flexibleCloudlets; + if (!/diskspace/.test('${this.storage.diskspace}')) + diskspace = String(node.diskLimit) != '${this.storage.diskspace}' ? '${this.storage.diskspace}' : node.diskLimit; + } + + nodes.push({ + flexibleCloudlets: cloudlets, + fixedCloudlets: node.fixedCloudlets, + nodeType: node.nodeType, + nodeGroup: node.nodeGroup, + diskLimit: diskspace, + count: count + }); + } + } + resp = api.env.control.ChangeTopology({ + envName: targetAppid, + session: session, + env: env, + nodes: nodes + }); + } + return { result: 0 }; diff --git a/scripts/events.jps b/scripts/events.jps new file mode 100755 index 0000000..9f37a8b --- /dev/null +++ b/scripts/events.jps @@ -0,0 +1,66 @@ +type: update +id: wordpress-cluster-events +name: WordPress Cluster Events +baseUrl: https://raw.githubusercontent.com/jelastic-jps/wordpress-cluster/v2.2.0 + +onAfterScaleOut[nodeGroup:bl]: setupCacheSync + +onAfterScaleIn[bl]: setupCacheSync + +onAfterScaleIn[cp]: updateTriggers + +onAfterScaleOut[nodeGroup:cp]: updateTriggers + +onAfterStart: + cmd[cp]: sudo jem service restart + +onAfterInstallAddon [nodeGroup:bl, id:letsencrypt-ssl-addon]: + - cmd[${nodes.bl.master.id}]: source /opt/letsencrypt/settings && echo $domain + - cmd[${nodes.cp.master.id}]: bash ~/bin/setupWP.sh --url https://${response.out}; + +onAfterClone: + - install: /scripts/setupHA4LB.jps?_r=${fn.random} + envName: ${event.response.env.envName} + + - install: /scripts/balancerRebuild.jps?_r=${fn.random} + envName: ${event.response.env.envName} + + - install: /scripts/setupDomain.jps?_r=${fn.random} + envName: ${event.response.env.envName} + settings: + domain: ${event.response.env.domain} + + - install: /scripts/cacheClean.jps?_r=${fn.random} + envName: ${event.response.env.envName} + + - script: delete MANIFEST.id; return {result:0, jps:MANIFEST}; + - install: ${response.jps} + envName: ${event.response.env.envName} + +onBeforeMigrate: + - cmd[${nodes.cp.master.id}]: wp option get siteurl --path=/var/www/webroot/ROOT | cut -d'/' -f3; + - if (/${response.out}/.test(env.domain)): + cmd[${nodes.cp.master.id}]: echo true > ~/migrate + - else: + cmd[${nodes.cp.master.id}]: echo false > ~/migrate + +onAfterMigrate: + - install: /scripts/setupHA4LB.jps?_r=${fn.random} + - install: /scripts/balancerRebuild.jps?_r=${fn.random} + - cmd[${nodes.cp.master.id}]: if test -f ~/migrate; then cat ~/migrate; fi + - if (/${response.out}/.test(true)): + - install: /scripts/setupDomain.jps?_r=${fn.random} + settings: + domain: ${env.domain} + - install: /scripts/cacheClean.jps?_r=${fn.random} + +actions: + setupCacheSync: + - if (/litespeed/.test("${nodes.bl.nodeType}")): + - install: /scripts/setupHA4LB.jps?_r=${fn.random} + + updateTriggers: + if (!${event.params.auto:true}): + - log: update scaling trigger + - script: /scripts/updateTriggers.js + count: ${nodes.cp.length} diff --git a/scripts/firewallRules.js b/scripts/firewallRules.js new file mode 100755 index 0000000..2e820c0 --- /dev/null +++ b/scripts/firewallRules.js @@ -0,0 +1,41 @@ +var envName = "${env.name}", + bFireWallEnabled, + outputRule, + inputRule, + rules, + resp; + +inputRule = { + "direction": "INPUT", + "name": name, + "protocol": "ALL", + "ports": ports, + "src": "ALL", + "priority": 1080, + "action": "ALLOW" +}; +outputRule = { + "direction":'OUTPUT', + "name":name, + "protocol":'ALL', + "ports":ports, + "dst":'ALL', + "priority":1000, + "action":'ALLOW' +}; + +if (jelastic.environment.security) { + resp = jelastic.billing.account.GetOwnerQuotas(appid, session, 'firewall.enabled'); + if (!resp || resp.result !== 0) return resp; + bFireWallEnabled = resp.array[0] ? resp.array[0].value : 0; + if (bFireWallEnabled) { + resp = jelastic.environment.security.AddRule(envName, session, inputRule, nodeGroup); + if (!resp || resp.result !== 0) return resp; + return jelastic.environment.security.AddRule(envName, session, outputRule, nodeGroup); + } +} + +return { + result: 0 +} + diff --git a/scripts/idna.js b/scripts/idna.js new file mode 100755 index 0000000..47f4c24 --- /dev/null +++ b/scripts/idna.js @@ -0,0 +1,332 @@ +//Javascript Punycode converter derived from example in RFC3492. +//This implementation is created by some@domain.name and released into public domain + +var domains = getParam("domains", ""), + parsed = []; + +var punycode = new function Punycode() { + // This object converts to and from puny-code used in IDN + // + // punycode.ToASCII ( domain ) + // + // Returns a puny coded representation of "domain". + // It only converts the part of the domain name that + // has non ASCII characters. I.e. it dosent matter if + // you call it with a domain that already is in ASCII. + // + // punycode.ToUnicode (domain) + // + // Converts a puny-coded domain name to unicode. + // It only converts the puny-coded parts of the domain name. + // I.e. it dosent matter if you call it on a string + // that already has been converted to unicode. + // + // + this.utf16 = { + // The utf16-class is necessary to convert from javascripts internal character representation to unicode and back. + decode:function(input){ + var output = [], i=0, len=input.length,value,extra; + while (i < len) { + value = input.charCodeAt(i++); + if ((value & 0xF800) === 0xD800) { + extra = input.charCodeAt(i++); + if ( ((value & 0xFC00) !== 0xD800) || ((extra & 0xFC00) !== 0xDC00) ) { + throw new RangeError("UTF-16(decode): Illegal UTF-16 sequence"); + } + value = ((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000; + } + output.push(value); + } + return output; + }, + encode:function(input){ + var output = [], i=0, len=input.length,value; + while (i < len) { + value = input[i++]; + if ( (value & 0xF800) === 0xD800 ) { + throw new RangeError("UTF-16(encode): Illegal UTF-16 value"); + } + if (value > 0xFFFF) { + value -= 0x10000; + output.push(String.fromCharCode(((value >>>10) & 0x3FF) | 0xD800)); + value = 0xDC00 | (value & 0x3FF); + } + output.push(String.fromCharCode(value)); + } + return output.join(""); + } + } + + //Default parameters + var initial_n = 0x80; + var initial_bias = 72; + var delimiter = "\x2D"; + var base = 36; + var damp = 700; + var tmin=1; + var tmax=26; + var skew=38; + var maxint = 0x7FFFFFFF; + + // decode_digit(cp) returns the numeric value of a basic code + // point (for use in representing integers) in the range 0 to + // base-1, or base if cp is does not represent a value. + + function decode_digit(cp) { + return cp - 48 < 10 ? cp - 22 : cp - 65 < 26 ? cp - 65 : cp - 97 < 26 ? cp - 97 : base; + } + + // encode_digit(d,flag) returns the basic code point whose value + // (when used for representing integers) is d, which needs to be in + // the range 0 to base-1. The lowercase form is used unless flag is + // nonzero, in which case the uppercase form is used. The behavior + // is undefined if flag is nonzero and digit d has no uppercase form. + + function encode_digit(d, flag) { + return d + 22 + 75 * (d < 26) - ((flag != 0) << 5); + // 0..25 map to ASCII a..z or A..Z + // 26..35 map to ASCII 0..9 + } + //** Bias adaptation function ** + function adapt(delta, numpoints, firsttime ) { + var k; + delta = firsttime ? Math.floor(delta / damp) : (delta >> 1); + delta += Math.floor(delta / numpoints); + + for (k = 0; delta > (((base - tmin) * tmax) >> 1); k += base) { + delta = Math.floor(delta / ( base - tmin )); + } + return Math.floor(k + (base - tmin + 1) * delta / (delta + skew)); + } + + // encode_basic(bcp,flag) forces a basic code point to lowercase if flag is zero, + // uppercase if flag is nonzero, and returns the resulting code point. + // The code point is unchanged if it is caseless. + // The behavior is undefined if bcp is not a basic code point. + + function encode_basic(bcp, flag) { + bcp -= (bcp - 97 < 26) << 5; + return bcp + ((!flag && (bcp - 65 < 26)) << 5); + } + + // Main decode + this.decode=function(input,preserveCase) { + // Dont use utf16 + var output=[]; + var case_flags=[]; + var input_length = input.length; + + var n, out, i, bias, basic, j, ic, oldi, w, k, digit, t, len; + + // Initialize the state: + + n = initial_n; + i = 0; + bias = initial_bias; + + // Handle the basic code points: Let basic be the number of input code + // points before the last delimiter, or 0 if there is none, then + // copy the first basic code points to the output. + + basic = input.lastIndexOf(delimiter); + if (basic < 0) basic = 0; + + for (j = 0; j < basic; ++j) { + if(preserveCase) case_flags[output.length] = ( input.charCodeAt(j) -65 < 26); + if ( input.charCodeAt(j) >= 0x80) { + throw new RangeError("Illegal input >= 0x80"); + } + output.push( input.charCodeAt(j) ); + } + + // Main decoding loop: Start just after the last delimiter if any + // basic code points were copied; start at the beginning otherwise. + + for (ic = basic > 0 ? basic + 1 : 0; ic < input_length; ) { + + // ic is the index of the next character to be consumed, + + // Decode a generalized variable-length integer into delta, + // which gets added to i. The overflow checking is easier + // if we increase i as we go, then subtract off its starting + // value at the end to obtain delta. + for (oldi = i, w = 1, k = base; ; k += base) { + if (ic >= input_length) { + throw RangeError ("punycode_bad_input(1)"); + } + digit = decode_digit(input.charCodeAt(ic++)); + + if (digit >= base) { + throw RangeError("punycode_bad_input(2)"); + } + if (digit > Math.floor((maxint - i) / w)) { + throw RangeError ("punycode_overflow(1)"); + } + i += digit * w; + t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias; + if (digit < t) { break; } + if (w > Math.floor(maxint / (base - t))) { + throw RangeError("punycode_overflow(2)"); + } + w *= (base - t); + } + + out = output.length + 1; + bias = adapt(i - oldi, out, oldi === 0); + + // i was supposed to wrap around from out to 0, + // incrementing n each time, so we'll fix that now: + if ( Math.floor(i / out) > maxint - n) { + throw RangeError("punycode_overflow(3)"); + } + n += Math.floor( i / out ) ; + i %= out; + + // Insert n at position i of the output: + // Case of last character determines uppercase flag: + if (preserveCase) { case_flags.splice(i, 0, input.charCodeAt(ic -1) -65 < 26);} + + output.splice(i, 0, n); + i++; + } + if (preserveCase) { + for (i = 0, len = output.length; i < len; i++) { + if (case_flags[i]) { + output[i] = (String.fromCharCode(output[i]).toUpperCase()).charCodeAt(0); + } + } + } + return this.utf16.encode(output); + }; + + //** Main encode function ** + + this.encode = function (input,preserveCase) { + //** Bias adaptation function ** + + var n, delta, h, b, bias, j, m, q, k, t, ijv, case_flags; + + if (preserveCase) { + // Preserve case, step1 of 2: Get a list of the unaltered string + case_flags = this.utf16.decode(input); + } + // Converts the input in UTF-16 to Unicode + input = this.utf16.decode(input.toLowerCase()); + + var input_length = input.length; // Cache the length + + if (preserveCase) { + // Preserve case, step2 of 2: Modify the list to true/false + for (j=0; j < input_length; j++) { + case_flags[j] = input[j] != case_flags[j]; + } + } + + var output=[]; + + + // Initialize the state: + n = initial_n; + delta = 0; + bias = initial_bias; + + // Handle the basic code points: + for (j = 0; j < input_length; ++j) { + if ( input[j] < 0x80) { + output.push( + String.fromCharCode( + case_flags ? encode_basic(input[j], case_flags[j]) : input[j] + ) + ); + } + } + + h = b = output.length; + + // h is the number of code points that have been handled, b is the + // number of basic code points + + if (b > 0) output.push(delimiter); + + // Main encoding loop: + // + while (h < input_length) { + // All non-basic code points < n have been + // handled already. Find the next larger one: + + for (m = maxint, j = 0; j < input_length; ++j) { + ijv = input[j]; + if (ijv >= n && ijv < m) m = ijv; + } + + // Increase delta enough to advance the decoder's + // state to , but guard against overflow: + + if (m - n > Math.floor((maxint - delta) / (h + 1))) { + throw RangeError("punycode_overflow (1)"); + } + delta += (m - n) * (h + 1); + n = m; + + for (j = 0; j < input_length; ++j) { + ijv = input[j]; + + if (ijv < n ) { + if (++delta > maxint) return Error("punycode_overflow(2)"); + } + + if (ijv == n) { + // Represent delta as a generalized variable-length integer: + for (q = delta, k = base; ; k += base) { + t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias; + if (q < t) break; + output.push( String.fromCharCode(encode_digit(t + (q - t) % (base - t), 0)) ); + q = Math.floor( (q - t) / (base - t) ); + } + output.push( String.fromCharCode(encode_digit(q, preserveCase && case_flags[j] ? 1:0 ))); + bias = adapt(delta, h + 1, h == b); + delta = 0; + ++h; + } + } + + ++delta, ++n; + } + return output.join(""); + } + + this.ToASCII = function ( domain ) { + var domain_array = domain.split("."); + var out = []; + for (var i=0; i < domain_array.length; ++i) { + var s = domain_array[i]; + out.push( + s.match(/[^A-Za-z0-9-]/) ? + "xn--" + punycode.encode(s) : + s + ); + } + return out.join("."); + } + this.ToUnicode = function ( domain ) { + var domain_array = domain.split("."); + var out = []; + for (var i=0; i < domain_array.length; ++i) { + var s = domain_array[i]; + out.push( + s.match(/^xn--/) ? + punycode.decode(s.slice(4)) : + s + ); + } + return out.join("."); + } +}(); + +domains = domains.split(','); + +for (var i = 0, n = domains.length; i < n; i++) { + parsed.push(punycode.ToASCII(String(java.lang.String(domains[i]).trim()))); +} + +return { result: 0, domains: parsed } diff --git a/scripts/installWP.jps b/scripts/installWP.jps new file mode 100755 index 0000000..c4b73ef --- /dev/null +++ b/scripts/installWP.jps @@ -0,0 +1,82 @@ +jpsType: update +id: wordpress-core-installation +name: WordPress Core Installation +description: WordPress Core Installation + +mixins: + - https://raw.githubusercontent.com/jelastic-jps/wordpress/master/configs/vers.yaml + +globals: + WP_ADMIN_PASS: ${settings.wp_admin_pass} + WP_TITLE: ${settings.wp_title} + DB_HOST: ${settings.db_host} + DB_NAME: wp_${fn.random} + DB_USER: ${settings.db_user} + DB_PASS: ${settings.db_pass} + REDIS_HOST: ${settings.redis_host:} + REDIS_PORT: ${settings.redis_port:} + REDIS_USER: ${settings.redis_user:} + REDIS_PSWD: ${settings.redis_pswd:} + WP_URL: ${settings.wp_url} + CLUSTER: ${settings.cluster:true} + +onInstall: + - deployWordPress + - installScripts + - installWordPress + - setupWordPress + - installPlugins + - setupPlugins + +actions: + deployWordPress: + - cmd[${nodes.cp.master.id}]: |- + #wget -qO /tmp/wordpress.tar.gz 'https://wordpress.org/wordpress-${globals.version_wordpress}.tar.gz'; + wget -qO /tmp/wordpress.tar.gz 'https://wordpress.org/latest.tar.gz'; + [ -d /tmp/wordpress/ ] && rm -rf /tmp/wordpress; + tar -xzf /tmp/wordpress.tar.gz -C /tmp/; + rsync -a /tmp/wordpress/* /var/www/webroot/ROOT/; + rsync -a --checksum /tmp/wordpress/* /var/www/webroot/ROOT/; + - addContext [cp]: + name: ROOT + fileName: WordPress + type: ARCHIVE + + installWordPress: + cmd[${nodes.cp.master.id}]: |- + mysql -u${globals.DB_USER} -p${globals.DB_PASS} -h ${nodes.sqldb.master.intIP} -e "CREATE DATABASE IF NOT EXISTS ${globals.DB_NAME};" + cd /var/www/webroot/ROOT && wp core config --dbhost=${nodes.sqldb.master.intIP} --dbname=${globals.DB_NAME} --dbuser=${globals.DB_USER} --dbpass=${globals.DB_PASS} --path=/var/www/webroot/ROOT; + cd /var/www/webroot/ROOT && wp core install --title="${globals.WP_TITLE}" --admin_user=${user.email} --admin_password=${globals.WP_ADMIN_PASS} --url=${globals.WP_URL} --admin_email=${user.email} --skip-email --path=/var/www/webroot/ROOT; + mv /var/www/webroot/ROOT/wp-config.php /tmp; sed -i "s/${nodes.sqldb.master.intIP}/${globals.DB_HOST}/g" /tmp/wp-config.php; mv /tmp/wp-config.php /var/www/webroot/ROOT; + wget ${baseUrl}../images/favicon.ico -O /var/www/webroot/ROOT/favicon.ico; + - if ('${globals.CLUSTER}' == 'true'): + + installScripts: + - cmd[cp]: |- + [ ! -d $HOME/bin ] && mkdir $HOME/bin; + curl -o $HOME/bin/wp https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar && chmod +x $HOME/bin/wp; + echo "apache_modules:" > ~/bin/wp-cli.yml; + echo " - mod_rewrite" >> ~/bin/wp-cli.yml; + echo "export PATH=$PATH:$HOME/bin/" >> $HOME/.bash_profile; + wget ${baseUrl}/setupWP.sh?_r=${fn.random} -O ~/bin/setupWP.sh &>> /var/log/run.log; + echo $HOME/bin; + - cmd[cp]: + echo ${response.out} >> /etc/jelastic/redeploy.conf; + yum install jq -y &>> /var/log/run.log; + user: root + + setupWordPress: + - cmd[${nodes.cp.master.id}]: |- + grep -qE "(WP_AUTO_UPDATE_CORE)" /var/www/webroot/ROOT/wp-config.php || sed -i "/^\$table_prefix.*/a define( 'WP_AUTO_UPDATE_CORE', false );" /var/www/webroot/ROOT/wp-config.php; + cd ~/bin/ && wp option update permalink_structure '/%postname%/' --path=/var/www/webroot/ROOT; + cd ~/bin/ && wp rewrite structure '/%postname%/' --hard --path=/var/www/webroot/ROOT; + + installPlugins: + - if (/llsmp/.test("${nodes.cp.nodeType}") || /litespeed/.test("${nodes.cp.nodeType}")): + cmd[${nodes.cp.master.id}]: |- + wp plugin install litespeed-cache --version=${globals.version_lscache} --activate --path=/var/www/webroot/ROOT &>> /var/log/run.log; + wp cache flush --path=/var/www/webroot/ROOT &>> /var/log/run.log; + + setupPlugins: + - cmd[${nodes.cp.master.id}]: |- + bash ~/bin/setupWP.sh --pgcache true --objectcache true --REDIS_HOST ${globals.REDIS_HOST} --REDIS_PORT ${globals.REDIS_PORT} --REDIS_USER ${globals.REDIS_USER} --REDIS_PSWD ${globals.REDIS_PSWD}; \ No newline at end of file diff --git a/scripts/settingsLS.js b/scripts/settingsLS.js new file mode 100755 index 0000000..b35bb6a --- /dev/null +++ b/scripts/settingsLS.js @@ -0,0 +1,158 @@ +import com.hivext.api.Response; +import org.yaml.snakeyaml.Yaml; +import com.hivext.api.core.utils.Transport; + +var cdnAppid = "c05ffa5b45628a2a0c95467ebca8a0b4"; +var lsAppid = "9e6afcf310004ac84060f90ff41a5aba"; +var group = jelastic.billing.account.GetAccount(appid, session); +var isCDN = jelastic.dev.apps.GetApp(cdnAppid); +var isLS = jelastic.dev.apps.GetApp(lsAppid); + +//checking quotas +var perEnv = "environment.maxnodescount", + maxEnvs = "environment.maxcount", + perNodeGroup = "environment.maxsamenodescount", + maxCloudletsPerRec = "environment.maxcloudletsperrec"; +var nodesPerEnvWO_Bl = 9, + nodesPerEnvWO_GlusterFS = 7, + nodesPerEnvMin = 6, + nodesPerGroupMin = 2, + maxCloudlets = 16, + markup = "", cur = null, text = "used", prod = true; + +var settings = jps.settings; +var fields = {}; +for (var i = 0, field; field = jps.settings.fields[i]; i++) + fields[field.name] = field; + +var quotas = jelastic.billing.account.GetQuotas(perEnv + ";"+maxEnvs+";" + perNodeGroup + ";" + maxCloudletsPerRec ).array; +var group = jelastic.billing.account.GetAccount(appid, session); +for (var i = 0; i < quotas.length; i++){ + var q = quotas[i], n = toNative(q.quota.name); + + if (n == maxCloudletsPerRec && maxCloudlets > q.value){ + err(q, "required", maxCloudlets, true); + prod = false; + } + + if (n == perEnv && nodesPerEnvMin > q.value){ + if (!markup) err(q, "required", nodesPerEnvMin, true); + prod = false; + } + + if (n == perNodeGroup && nodesPerGroupMin > q.value){ + if (!markup) err(q, "required", nodesPerGroupMin, true); + prod = false; + } + + if (n == perEnv && nodesPerEnvMin == q.value){ + fields["glusterfs"].value = false; + fields["glusterfs"].disabled = true; + fields["galera"].value = false; + fields["galera"].disabled = true; + fields["bl_count"].value = 1; + fields["displayfield"].markup = "Some advanced features are not available. Please upgrade your account."; + fields["displayfield"].cls = "warning"; + fields["displayfield"].hideLabel = true; + fields["displayfield"].height = 25; + } + + if (n == perEnv && nodesPerEnvWO_GlusterFS == q.value){ + fields["glusterfs"].value = false; + fields["glusterfs"].disabled = true; + fields["bl_count"].value = 1; + fields["displayfield"].markup = "Some advanced features are not available. Please upgrade your account."; + fields["displayfield"].cls = "warning"; + fields["displayfield"].hideLabel = true; + fields["displayfield"].height = 25; + } + + if (n == perEnv && q.value == 8){ + fields["glusterfs"].value = false; + fields["glusterfs"].disabled = true; + fields["bl_count"].value = 2; + fields["displayfield"].markup = "Some advanced features are not available. Please upgrade your account."; + fields["displayfield"].cls = "warning"; + fields["displayfield"].hideLabel = true; + fields["displayfield"].height = 25; + } + + if (n == perEnv && nodesPerEnvWO_Bl == q.value){ + fields["bl_count"].value = 1; + } + + if (n == perNodeGroup && nodesPerGroupMin == q.value){ + fields["glusterfs"].value = false; + fields["glusterfs"].disabled = true; + fields["galera"].value = false; + fields["galera"].disabled = true; + fields["displayfield"].markup = "Some advanced features are not available. Please upgrade your account."; + fields["displayfield"].cls = "warning"; + fields["displayfield"].hideLabel = true; + fields["displayfield"].height = 25; + } + + if (isLS.result == 0 || isLS.result == Response.PERMISSION_DENIED) { + fields["ls-addon"].hidden = false; + fields["ls-addon"].value = true; + } else { + fields["ls-addon"].hidden = true; + fields["ls-addon"].value = false; + fields["ls-addon"].showIf = null; + } + + if (isCDN.result == 0 || isCDN.result == Response.PERMISSION_DENIED) { + fields["cdn-addon"].hidden = false; + fields["cdn-addon"].value = true; + } else { + fields["cdn-addon"].hidden = true; + fields["cdn-addon"].value = false; + } + + var extIP = jelastic.billing.account.GetQuotas('environment.externalip.enabled'); + var extIPperEnv = jelastic.billing.account.GetQuotas('environment.externalip.maxcount'); + var extIPperNode = jelastic.billing.account.GetQuotas('environment.externalip.maxcount.per.node'); + + if ((extIP.result == 0 && extIP.array[0].value) && (extIPperEnv.result == 0 && extIPperEnv.array[0].value >= 2) && (extIPperNode.result == 0 && extIPperNode.array[0].value >= 1)) { + fields["le-addon"].disabled = false; + fields["le-addon"].value = true; + } +} + +if (!prod) { + fields["ls-addon"].disabled = true; + fields["ls-addon"].value = false; + fields["loadGrowth"].disabled = true; + fields["galera"].disabled = true; + fields["galera"].value = false; + fields["glusterfs"].disabled = true; + fields["glusterfs"].value = false; + fields["le-addon"].disabled = true; + fields["le-addon"].value = false; + fields["cdn-addon"].disabled = true; + fields["cdn-addon"].value = false; + fields["mu-addon"].disabled = true; + fields["displayfield"].markup = "Advanced features are not available."; + fields["displayfield"].cls = "warning"; + fields["displayfield"].hideLabel = true; + fields["displayfield"].height = 25; + fields["bl_count"].markup = "WordPress cluster is not available. " + markup + "Please upgrade your account."; + fields["bl_count"].cls = "warning"; + fields["bl_count"].hidden = false; + fields["bl_count"].height = 30; + + + settings.fields.push( + {"type": "compositefield","height": 0,"hideLabel": true,"width": 0,"items": [{"height": 0,"type": "string","required": true}]} + ); +} + +return { + result: 0, + settings: settings +}; + +function err(e, text, cur, override){ + var m = (e.quota.description || e.quota.name) + " - " + e.value + ", " + text + " - " + cur + ". "; + if (override) markup = m; else markup += m; +} diff --git a/scripts/setupDomain.jps b/scripts/setupDomain.jps new file mode 100755 index 0000000..72b2842 --- /dev/null +++ b/scripts/setupDomain.jps @@ -0,0 +1,9 @@ +type: update +id: setup-wordpress-domain +name: Setup WordPress Domain + +globals: + DOMAIN: ${settings.domain} + +onInstall: + - cmd[${nodes.cp.master.id}]: bash ~/bin/setupWP.sh --domain ${globals.DOMAIN} diff --git a/scripts/setupHA4LB.jps b/scripts/setupHA4LB.jps new file mode 100755 index 0000000..7040f9e --- /dev/null +++ b/scripts/setupHA4LB.jps @@ -0,0 +1,57 @@ +jpsType: update +name: Setup HA for Load Balancer +id: setup-ha4lb + +onInstall: + + - if ('${nodes.bl.master.nodeType}' == 'litespeedadc' && nodes.bl.length > 1): + - script[bl]: firewallRules.js?_r=${fn.random} + ports: '1447' + name: LSADC-HA + + - resetReplClusters + - forEach(i:nodes.bl): + - setupInstance: + id: "${@i.id}" + ip: "${@i.address}" + - setupReplClusters + - restartNodesInOrder + - cacheClean + + - if ('${nodes.bl.master.nodeType}' == 'litespeedadc' && nodes.bl.length == 1): resetReplClusters + +actions: + resetReplClusters: + cmd[bl]: |- + echo "" > /var/www/conf/ha_config.xml; + echo "" >> /var/www/conf/ha_config.xml; + + setupReplClusters: + script: + - var resp = jelastic.env.control.GetEnvInfo('${env.envName}', session); + - if (resp.result != 0) return resp; + - var nodes = []; + - for (var i = 0, n = resp.nodes; i < n.length; i++) + - " n[i].nodeGroup == nodeGroup ? nodes.push(n[i].address + ':1447') : 0" + - 'resp = {result:0, onAfterReturn: {}};' + - resp.onAfterReturn['cmd['+ nodeGroup +']'] = '/usr/bin/xmlstarlet ed --inplace -s "haConfig/replication" -t elem -n "replCluster" + -v "'+ nodes.join(',') +'" "/var/www/conf/ha_config.xml" 2>/dev/null;' + - return resp; + nodeGroup: bl + + setupInstance: + cmd[${this.id}]: |- + /usr/bin/xmlstarlet ed --inplace -s "haConfig" -t elem -n "replication" "/var/www/conf/ha_config.xml" 2>/dev/null; + /usr/bin/xmlstarlet ed --inplace -s "haConfig/replication" -t elem -n "serverAddr" -v "${this.ip}:1447" "/var/www/conf/ha_config.xml" 2>/dev/null; + /usr/bin/xmlstarlet ed --inplace -s "haConfig/replication" -t elem -n "isFileCached" -v "1" "/var/www/conf/ha_config.xml" 2>/dev/null; + + restartNodesInOrder: + - forEach(i:nodes.bl): + - cmd[${@i.id}]: |- + pkill -9 lslbd; + jem service restart; + user: root + + cacheClean: + cmd[bl]: |- + [ -d /tmp/lscache/vhosts/Jelastic/ ] && rm -rf /tmp/lscache/vhosts/Jelastic/* &>> /var/log/run.log; diff --git a/scripts/setupWP.sh b/scripts/setupWP.sh new file mode 100755 index 0000000..0449bf5 --- /dev/null +++ b/scripts/setupWP.sh @@ -0,0 +1,314 @@ +#!/bin/bash -e + +purge=false; +pgcache=false; +objectcache=false; +edgeportCDN=false; +multisite=false; +domain=false; +url=false; +woocommerce=false; + +SERVER_WEBROOT=/var/www/webroot/ROOT + +ARGUMENT_LIST=( + "purge" + "pgcache" + "objectcache" + "edgeportCDN" + "multisite" + "REDIS_HOST" + "REDIS_PORT" + "REDIS_USER" + "REDIS_PSWD" + "CDN_URL" + "CDN_ORI" + "mode" + "url" + "domain" + "ENV_NAME" + "woocommerce" + +) + +WP=`which wp` + +# read arguments +opts=$(getopt \ + --longoptions "$(printf "%s:," "${ARGUMENT_LIST[@]}")" \ + --name "$(basename "$0")" \ + --options "" \ + -- "$@" +) +eval set --$opts + +while [[ $# -gt 0 ]]; do + case "$1" in + --purge) + purge=$2 + shift 2 + ;; + + --pgcache) + pgcache=$2 + shift 2 + ;; + + --objectcache) + objectcache=$2 + shift 2 + ;; + + --edgeportCDN) + edgeportCDN=$2 + shift 2 + ;; + + --REDIS_HOST) + REDIS_HOST=$2 + shift 2 + ;; + + --REDIS_PORT) + REDIS_PORT=$2 + shift 2 + ;; + + --REDIS_USER) + REDIS_USER=$2 + shift 2 + ;; + + --REDIS_PSWD) + REDIS_PSWD=$2 + shift 2 + ;; + + --CDN_URL) + CDN_URL=$2 + shift 2 + ;; + + --CDN_ORI) + CDN_ORI=$2 + shift 2 + ;; + + --multisite) + multisite=$2 + shift 2 + ;; + + --mode) + mode=$2 + shift 2 + ;; + + --url) + url=$2 + shift 2 + ;; + + --domain) + domain=$2 + shift 2 + ;; + + --ENV_NAME) + ENV_NAME=$2 + shift 2 + ;; + + --woocommerce) + woocommerce=$2 + shift 2 + ;; + + *) + break + ;; + esac +done + +W3TC_OPTION_SET="${WP} w3-total-cache option set" +LSCWP_OPTION_SET="${WP} litespeed-option set" +lOG="/var/log/run.log" + +COMPUTE_TYPE=$(grep "COMPUTE_TYPE=" /etc/jelastic/metainf.conf | cut -d"=" -f2) + +cd ${SERVER_WEBROOT}; + +if [[ ${COMPUTE_TYPE} == *"llsmp"* || ${COMPUTE_TYPE} == *"litespeed"* ]] ; then + CACHE_FLUSH="${WP} litespeed-purge all --path=${SERVER_WEBROOT}; rm -rf /var/www/webroot/.cache/vhosts/Jelastic/* " + WPCACHE='lscwp'; +elif [[ ${COMPUTE_TYPE} == *"lemp"* || ${COMPUTE_TYPE} == *"nginx"* ]] ; then + CACHE_FLUSH="${WP} w3-total-cache flush all --path=${SERVER_WEBROOT}; /var/www/webroot/.cache/* " + WPCACHE="w3tc"; +else + echo 'Compute type is not defined'; + exit; +fi + +function generateCdnContent () { + echo "wp-content/themes/twentytwentytwo/style.css" > ~/checkCdnContent.txt; + echo "wp-includes/css/dist/block-library/style.min.css" >> ~/checkCdnContent.txt; + echo "wp-includes/css/dist/block-library/theme.min.css" >> ~/checkCdnContent.txt; + echo "wp-includes/js/wp-embed.min.js" >> ~/checkCdnContent.txt; +} + +function checkCdnStatus () { +if [ $WPCACHE == 'w3tc' ] ; then + CDN_ENABLE_CMD="${WP} w3-total-cache option set cdn.enabled true --type=boolean" +elif [ $WPCACHE == 'lscwp' ] ; then + CDN_ENABLE_CMD="${WP} litespeed-option set cdn true" +fi +cat > ~/checkCdnStatus.sh <> /var/log/run.log +${CACHE_FLUSH} &>> /var/log/run.log +${WP} cache flush --path=${SERVER_WEBROOT} &>> /var/log/run.log +crontab -l | sed "/checkCdnStatus/d" | crontab - +EOF +chmod +x ~/checkCdnStatus.sh +PROTOCOL=$(${WP} option get siteurl --path=${SERVER_WEBROOT} | cut -d':' -f1) +crontab -l | { cat; echo "* * * * * /bin/bash ~/checkCdnStatus.sh ${PROTOCOL}://${CDN_URL}/"; } | crontab +} + +if [ $purge == 'true' ] ; then + ${CACHE_FLUSH} &>> /var/log/run.log + ${WP} cache flush --path=${SERVER_WEBROOT} &>> /var/log/run.log + [ -d /tmp/lscache/vhosts/ ] && /usr/bin/rm -rf /tmp/lscache/vhosts/Jelastic/* &>> /var/log/run.log +fi + +if [ $pgcache == 'true' ] ; then + case $WPCACHE in + w3tc) + $W3TC_OPTION_SET pgcache.enabled true --type=boolean --path=${SERVER_WEBROOT} &>> $lOG + $W3TC_OPTION_SET pgcache.file.nfs true --type=boolean --path=${SERVER_WEBROOT} &>> $lOG + ;; + lscwp) + ;; + esac +fi + +if [ $objectcache == 'true' ] ; then + case $WPCACHE in + w3tc) + $W3TC_OPTION_SET objectcache.enabled true --type=boolean --path=${SERVER_WEBROOT} &>> /var/log/run.log + $W3TC_OPTION_SET objectcache.engine redis --path=${SERVER_WEBROOT} &>> /var/log/run.log + $W3TC_OPTION_SET objectcache.redis.servers ${REDIS_HOST}:${REDIS_PORT} --path=${SERVER_WEBROOT} &>> /var/log/run.log + $W3TC_OPTION_SET objectcache.redis.password ${REDIS_PSWD} --path=${SERVER_WEBROOT} &>> /var/log/run.log + ;; + lscwp) + $LSCWP_OPTION_SET object true --path=${SERVER_WEBROOT} &>> /var/log/run.log; + $LSCWP_OPTION_SET object-kind 1 --path=${SERVER_WEBROOT} &>> /var/log/run.log; + + $LSCWP_OPTION_SET object-host '' --path=${SERVER_WEBROOT} &>> /var/log/run.log; + [[ ! -z "${REDIS_HOST}" ]] && $LSCWP_OPTION_SET object-host ${REDIS_HOST} --path=${SERVER_WEBROOT} &>> /var/log/run.log; + + $LSCWP_OPTION_SET object-port '' --path=${SERVER_WEBROOT} &>> /var/log/run.log; + [[ ! -z "${REDIS_PORT}" ]] && $LSCWP_OPTION_SET object-port ${REDIS_PORT} --path=${SERVER_WEBROOT} &>> /var/log/run.log; + + $LSCWP_OPTION_SET object-user '' --path=${SERVER_WEBROOT} &>> /var/log/run.log; + [[ ! -z "${REDIS_USER}" ]] && $LSCWP_OPTION_SET object-user ${REDIS_USER} --path=${SERVER_WEBROOT} &>> /var/log/run.log; + + $LSCWP_OPTION_SET object-pswd '' --path=${SERVER_WEBROOT} &>> /var/log/run.log; + [[ ! -z "${REDIS_PSWD}" ]] && $LSCWP_OPTION_SET object-pswd ${REDIS_PSWD} --path=${SERVER_WEBROOT} &>> /var/log/run.log; + ;; + esac +fi + +if [ $edgeportCDN == 'true' ] ; then + if ! $(${WP} core is-installed --network --path=${SERVER_WEBROOT}); then + case $WPCACHE in + w3tc) + generateCdnContent; + checkCdnStatus; + $W3TC_OPTION_SET cdn.enabled false --type=boolean --path=${SERVER_WEBROOT} &>> /var/log/run.log + $W3TC_OPTION_SET cdn.engine mirror --path=${SERVER_WEBROOT} &>> /var/log/run.log + $W3TC_OPTION_SET cdn.mirror.domain ${CDN_URL} --path=${SERVER_WEBROOT} &>> /var/log/run.log + ;; + lscwp) + generateCdnContent; + checkCdnStatus; + CDN_ORI=$(${WP} option get siteurl --path=${SERVER_WEBROOT} | cut -d'/' -f3) + PROTOCOL=$(${WP} option get siteurl --path=${SERVER_WEBROOT} | cut -d':' -f1) + $LSCWP_OPTION_SET cdn false --path=${SERVER_WEBROOT} &>> /var/log/run.log + $LSCWP_OPTION_SET cdn-mapping[url][0] ${PROTOCOL}://${CDN_URL}/ --path=${SERVER_WEBROOT} &>> /var/log/run.log + $LSCWP_OPTION_SET cdn-ori "//${CDN_ORI}/" --path=${SERVER_WEBROOT} &>> /var/log/run.log + ;; + esac + fi +fi + +if [ $multisite == 'true' ] ; then + cd ~/bin/ && ${WP} option update permalink_structure '' --path=/var/www/webroot/ROOT/ &>> /var/log/run.log; + cd ~/bin/ && ${WP} rewrite structure '' --hard --path=/var/www/webroot/ROOT/ &>> /var/log/run.log; + ${WP} cache flush --path=${SERVER_WEBROOT}; + case $WPCACHE in + w3tc) + ${WP} plugin deactivate w3-total-cache --path=${SERVER_WEBROOT} &>> /var/log/run.log; + [[ ${mode} == 'subdir' ]] && ${WP} core multisite-convert --path=${SERVER_WEBROOT} &>> /var/log/run.log; + [[ ${mode} == 'subdom' ]] && ${WP} core multisite-convert --path=${SERVER_WEBROOT} --subdomains &>> /var/log/run.log; + ${WP} plugin activate w3-total-cache --path=${SERVER_WEBROOT} &>> /var/log/run.log; + ;; + lscwp) + ${WP} plugin deactivate litespeed-cache --path=${SERVER_WEBROOT} &>> /var/log/run.log; + [[ ${mode} == 'subdir' ]] && ${WP} core multisite-convert --path=${SERVER_WEBROOT} &>> /var/log/run.log; + [[ ${mode} == 'subdom' ]] && ${WP} core multisite-convert --path=${SERVER_WEBROOT} --subdomains &>> /var/log/run.log; + ${WP} plugin activate litespeed-cache --network --path=${SERVER_WEBROOT} &>> /var/log/run.log; + ${WP} cache flush --path=${SERVER_WEBROOT}; + echo "Configuring litespeed.conf.cache" >> /var/log/run.log; + ${WP} db query "UPDATE wp_sitemeta set meta_value = 1 where meta_key = 'litespeed.conf.cache'" --path=${SERVER_WEBROOT} &>> /var/log/run.log; + ${WP} db query "select meta_value from wp_sitemeta where meta_key = 'litespeed.conf.cache'" --path=${SERVER_WEBROOT} &>> /var/log/run.log; + + echo "Configuring litespeed.conf.object" >> /var/log/run.log; + ${WP} db query "UPDATE wp_sitemeta set meta_value = 1 where meta_key = 'litespeed.conf.object'" --path=${SERVER_WEBROOT} &>> /var/log/run.log; + echo "Configuring litespeed.conf.object-kind" >> /var/log/run.log; + ${WP} db query "UPDATE wp_sitemeta set meta_value = 1 where meta_key = 'litespeed.conf.object-kind'" --path=${SERVER_WEBROOT} &>> /var/log/run.log; + + echo "Configuring litespeed.conf.object-host" >> /var/log/run.log; + ${WP} db query "UPDATE wp_sitemeta set meta_value = '/var/run/redis/redis.sock' where meta_key = 'litespeed.conf.object-host'" --path=${SERVER_WEBROOT} &>> /var/log/run.log; + + echo "Configuring litespeed.conf.object-port" >> /var/log/run.log; + ${WP} db query "UPDATE wp_sitemeta set meta_value = 0 where meta_key = 'litespeed.conf.object-port'" --path=${SERVER_WEBROOT} &>> /var/log/run.log; + ;; + esac + ${WP} cache flush --path=${SERVER_WEBROOT}; +fi + +if [ $url != 'false' ] ; then + if ! $(${WP} core is-installed --network --path=${SERVER_WEBROOT}); then + old_url=$(${WP} option get siteurl --path=${SERVER_WEBROOT}) + old_domain=$(${WP} option get siteurl --path=${SERVER_WEBROOT} | cut -d'/' -f3) + new_domain=$(echo $url | cut -d'/' -f3) + ${WP} search-replace "${old_url}" "${url}" --skip-columns=guid --all-tables --path=${SERVER_WEBROOT} &>> /var/log/run.log + ${WP} search-replace "${old_domain}" "${new_domain}" --skip-columns=guid --all-tables --path=${SERVER_WEBROOT} &>> /var/log/run.log + ${CACHE_FLUSH} &>> /var/log/run.log + ${WP} cache flush --path=${SERVER_WEBROOT} &>> /var/log/run.log + fi +fi + +if [ $domain != 'false' ] ; then + old_domain=$(${WP} option get siteurl --path=${SERVER_WEBROOT} | cut -d'/' -f3) + ${WP} search-replace "${old_domain}" "${domain}" --skip-columns=guid --all-tables --path=${SERVER_WEBROOT} &>> /var/log/run.log + ${CACHE_FLUSH} &>> /var/log/run.log + ${WP} cache flush --path=${SERVER_WEBROOT} &>> /var/log/run.log + if $(${WP} core is-installed --network --path=${SERVER_WEBROOT}); then + ${WP} config set DOMAIN_CURRENT_SITE ${domain} --path=${SERVER_WEBROOT} + fi +fi + +if [ $woocommerce == 'true' ] ; then + ${WP} plugin install woocommerce --activate --path=${SERVER_WEBROOT} &>> /var/log/run.log +fi diff --git a/scripts/updateTriggers.js b/scripts/updateTriggers.js new file mode 100755 index 0000000..7d43e08 --- /dev/null +++ b/scripts/updateTriggers.js @@ -0,0 +1,52 @@ +var SCALE = "scale-", + DOWN = "down", + UP = "up", + scaleUp = SCALE + UP, + scaleDown = SCALE + DOWN, + addNode = "ADD_NODE", + removeNode = "REMOVE_NODE", + count = getParam('count'), + ENV_NAME = "${env.name}", + triggersToEdit = [], + triggerActions, + customData, + triggers, + upLimit, + resp; + +resp = jelastic.environment.trigger.GetTriggers(ENV_NAME, session, addNode + ";" + removeNode); +if (resp.result != 0) return resp; + +triggers = resp.array; + +for (var i = 0, n = triggers.length; i < n; i++) { + if ([scaleUp, scaleDown].indexOf(String(triggers[i].name)) != -1) { + triggerActions = triggers[i].actions; + + for (var l = 0, m = triggerActions.length; l < m; l++) { + customData = triggerActions[l].customData; + + if (triggers[i].name == scaleUp) upLimit = customData.limit; + + if ((triggerActions[l].type == addNode && customData.limit < count) || triggerActions[l].type == removeNode) { + triggers[i].actions[l].customData.limit = count; + + triggersToEdit.push({ + scale: triggers[i].name.indexOf(UP) != -1 ? UP : DOWN, + trigger: triggers[i] + }); + } + } + } +} + +for (var i = 0, n = triggersToEdit.length; i < n; i++) { + trigger = triggersToEdit[i].trigger; + + if (triggersToEdit[i].scale == DOWN && trigger.actions[0].customData.limit >= upLimit) trigger.actions[0].customData.limit = upLimit - 1; + + resp = jelastic.environment.trigger.EditTrigger(ENV_NAME, session, trigger.id, trigger); + if (resp.result != 0) return resp; +} + +return {result: 0}; diff --git a/success/email/success.md b/success/email/success.md new file mode 100755 index 0000000..51f8972 --- /dev/null +++ b/success/email/success.md @@ -0,0 +1,30 @@ +**WordPress environment**: [${globals.PROTOCOL}://${env.domain}/](${globals.PROTOCOL}://${env.domain}/) + +Use the following credentials to access the admin panel: + +**Admin Panel**: [${globals.PROTOCOL}://${env.domain}/wp-admin/](${globals.PROTOCOL}://${env.domain}/wp-admin/) +**Login**: ${user.email} +**Password**: ${globals.WP_ADMIN_PASS} + +Use the following credentials to access the LiteSpeed ADC admin console: + +**Admin Console**: [https://node${nodes.bl.master.id}-${env.domain}:4848](https://node${nodes.bl.master.id}-${env.domain}:4848) +**Login**: admin +**Password**: ${globals.LS_ADMIN_PASS} + +**Note:** Every time when you need to make settings customization you should apply it to all the load balancer nodes via their admin panels. To access every load balancer admin panel use the same URL and just substitute the ${nodeId} value with respective one for every load balancer node. + +Use the following credentials to access the LiteSpeed WEB Server admin console: + +**Admin Console**: [https://node${nodes.cp.master.id}-${env.domain}:4848](https://node${nodes.cp.master.id}-${env.domain}:4848) +**Login**: admin +**Password**: ${globals.LS_ADMIN_PASS} + +**Note:** Every time when you need to make settings customization you should apply it to all the web server nodes via their admin panels. To access every web server admin panel use the same URL and just substitute the ${nodeId} value with respective one for every web server node. + +Manage the database nodes using the next credentials: + +**phpMyAdmin Panel**: [https://node${nodes.sqldb.master.id}-${env.domain}/](https://node${nodes.sqldb.master.id}-${env.domain}/) +**Username**: ${globals.DB_USER} +**Password**: ${globals.DB_PASS} + diff --git a/success/text/success.md b/success/text/success.md new file mode 100755 index 0000000..3da63d0 --- /dev/null +++ b/success/text/success.md @@ -0,0 +1,17 @@ +**WordPress environment**: [${globals.PROTOCOL}://${env.domain}/](${globals.PROTOCOL}://${env.domain}/) + +Use the following credentials to access the admin panel: + +**Admin Panel**: [${globals.PROTOCOL}://${env.domain}/wp-admin/](${globals.PROTOCOL}://${env.domain}/wp-admin/) +**Login**: ${user.email} +**Password**: ${globals.WP_ADMIN_PASS} + +The instructions below can help you with further managing your WordPress: + +* [Bind custom domain](https://docs.jelastic.com/custom-domain-via-cname) +* [Share access to the environment](http://docs.jelastic.com/share-environment) +* [Adjust automatic vertical scaling settings](http://docs.jelastic.com/automatic-vertical-scaling) +* [Configure automatic horizontal scaling](http://docs.jelastic.com/automatic-horizontal-scaling) +* [Monitor the statistics](http://docs.jelastic.com/view-app-statistics) & [view log files](https://docs.jelastic.com/view-log-files) +* [Attach Public IP](https://docs.jelastic.com/public-ip) +* [Access environment via SSH](https://docs.jelastic.com/ssh-access)