Thomas Cuthbert has proposed merging ~tcuthbert/charm-k8s-wordpress/+git/wordpress-k8s-image-builder:master into charm-k8s-wordpress:master.
Requested reviews: Wordpress Charmers (wordpress-charmers) For more details, see: https://code.launchpad.net/~tcuthbert/charm-k8s-wordpress/+git/wordpress-k8s-image-builder/+merge/394384 -- Your team Wordpress Charmers is requested to review the proposed merge of ~tcuthbert/charm-k8s-wordpress/+git/wordpress-k8s-image-builder:master into charm-k8s-wordpress:master.
diff --git a/.gitignore b/.gitignore index ed12673..f691d68 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,16 @@ +<<<<<<< .gitignore build *.charm .tox .coverage __pycache__ +======= +*.pyc +*.swp +*~ +__pycache__ +files/plugins/ +files/themes/ +.coverage +.tox/ +>>>>>>> .gitignore diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1ca1002 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,100 @@ +ARG DIST_RELEASE + +FROM ubuntu:${DIST_RELEASE} + +LABEL maintainer="wordpress-charmers@lists.launchpad.net" + +# HTTPS_PROXY used when we RUN curl to download Wordpress itself +ARG BUILD_DATE +ARG HTTPS_PROXY + +# Launchpad OCI image builds don't support dynamic arg parsing. Skip until +# https://bugs.launchpad.net/launchpad/+bug/1902010 is resolved. +#LABEL org.label-schema.build-date=${BUILD_DATE} + +ENV APACHE_CONFDIR=/etc/apache2 +ENV APACHE_ENVVARS=/etc/apache2/envvars + +# Avoid interactive prompts +RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections + +# Update all packages, remove cruft, install required packages, configure apache +RUN apt-get update && apt-get -y dist-upgrade \ + && apt-get --purge autoremove -y \ + && apt-get install -y apache2 \ + bzr \ + curl \ + git \ + libapache2-mod-php \ + libgmp-dev \ + php \ + php-curl \ + php-gd \ + php-gmp \ + php-mysql \ + php-symfony-yaml \ + php-xml \ + pwgen \ + python3 \ + python3-yaml \ + ssl-cert \ + && sed -ri 's/^export ([^=]+)=(.*)$/: ${\1:=\2}\nexport \1/' "$APACHE_ENVVARS" \ + && . "$APACHE_ENVVARS" \ + && for dir in "$APACHE_LOCK_DIR" "$APACHE_RUN_DIR" "$APACHE_LOG_DIR"; do rm -rvf "$dir"; mkdir -p "$dir"; chown "$APACHE_RUN_USER:$APACHE_RUN_GROUP" "$dir"; chmod 777 "$dir"; done \ + && ln -sfT /dev/stderr "$APACHE_LOG_DIR/error.log" \ + && ln -sfT /dev/stdout "$APACHE_LOG_DIR/access.log" \ + && ln -sfT /dev/stdout "$APACHE_LOG_DIR/other_vhosts_access.log" \ + && chown -R --no-dereference "$APACHE_RUN_USER:$APACHE_RUN_GROUP" "$APACHE_LOG_DIR" + +# Configure PHP and apache2 - mod_php requires us to use mpm_prefork +COPY ./files/docker-php.conf $APACHE_CONFDIR/conf-available/docker-php.conf +RUN a2enconf docker-php \ + && a2dismod mpm_event \ + && a2enmod headers \ + && a2enmod mpm_prefork \ + && a2enmod proxy \ + && a2enmod proxy_http \ + && a2enmod rewrite + +# Install the main Wordpress code, this will be our only site so /var/www/html is fine +RUN curl -o wordpress.tar.gz -fSL "https://wordpress.org/latest.tar.gz" \ + && tar -xzf wordpress.tar.gz -C /usr/src/ \ + && rm wordpress.tar.gz \ + && chown -R www-data:www-data /usr/src/wordpress \ + && rm -rf /var/www/html \ + && mv /usr/src/wordpress /var/www/html + +COPY ./files/ /files/ +COPY ./fetcher.py . +RUN mkdir -p /files/themes /files/plugins +RUN export HTTP_PROXY="" HTTPS_PROXY="" && ./fetcher.py +# Copy our collected themes and plugins into the appropriate paths +RUN cp -r /files/plugins/* /var/www/html/wp-content/plugins/ +RUN cp -r /files/themes/* /var/www/html/wp-content/themes/ + +# wp-info.php contains template variables which our ENTRYPOINT script will populate +RUN install -D /files/wp-info.php /var/www/html/wp-info.php +RUN install -D /files/wp-config.php /var/www/html/wp-config.php +RUN chown -R www-data:www-data /var/www/html + +# Copy our helper scripts and their wrapper into their own directory +RUN install /files/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh + +RUN install -t /srv/wordpress-helpers/ -D /files/_add_option.php \ + /files/_enable_plugin.php \ + /files/_get_option.php \ + /files/plugin_handler.py \ + /files/ready.sh + +# Make the wrapper executable +RUN chmod 0755 /srv/wordpress-helpers/plugin_handler.py +RUN chmod 0755 /srv/wordpress-helpers/ready.sh +RUN chmod 0755 /usr/local/bin/docker-entrypoint.sh + +RUN rm -r /files + +# Port 80 only, TLS will terminate elsewhere +EXPOSE 80 + +ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] +CMD apachectl -D FOREGROUND diff --git a/Makefile b/Makefile index c46ed23..a4ac36b 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,4 @@ +<<<<<<< Makefile wordpress.charm: src/*.py requirements.txt @echo "Building Kubernetes WordPress Charm." @charmcraft build @@ -27,3 +28,69 @@ clean: @rm -r ./build || true .PHONY: format lint test unittest integration clean +======= +DIST_RELEASE ?= bionic +VERSION ?= latest +DOCKER_DEPS = \ + apache2 \ + curl \ + libapache2-mod-php \ + libgmp-dev \ + php \ + php-curl \ + php-gd \ + php-gmp \ + php-mysql \ + php-symfony-yaml \ + php-xml \ + pwgen \ + python3 \ + python3-yaml \ + ssl-cert + +build-image: + @echo "Building the image." + @docker build \ + --no-cache=true \ + --build-arg BUILD_DATE=$$(date -u +'%Y-%m-%dT%H:%M:%SZ') \ + --build-arg PKGS_TO_INSTALL='$(DOCKER_DEPS)' \ + --build-arg DIST_RELEASE=$(DIST_RELEASE) \ + --build-arg HTTPS_PROXY=$(HTTPS_PROXY) \ + -t wordpress:$(DIST_RELEASE)-$(VERSION) \ + . + +build: lint deps fetch build-image + @echo "Pushing to the prod-is-external registry." + @docker tag wordpress:$(DIST_RELEASE)-$(VERSION) prod-is-external.docker-registry.canonical.com/wordpress:$(DIST_RELEASE)-$(VERSION) + @docker push prod-is-external.docker-registry.canonical.com/wordpress:$(DIST_RELEASE)-$(VERSION) + +deps: + @echo "Checking dependencies are present" + @command -v bzr >/dev/null 2>&1 || { echo "I require bzr but it's not installed. Aborting." >&2; exit 1; } + @command -v git >/dev/null 2>&1 || { echo "I require git but it's not installed. Aborting." >&2; exit 1; } + +fetch: + @echo "Fetching plugins and themes." + @tox -e fetch + +lint: clean + @echo "Running flake8" + @tox -e lint + +test: lint + @echo "Running unit tests" + @tox -e unit + +clean: + @echo "Cleaning files" + @rm -rf ./.tox + @rm -rf ./.pytest_cache + @rm -rf ./files/plugins/* + @rm -rf ./files/themes/* + @rm -rf ./files/__pycache__ + @rm -rf ./tests/unit/__pycache__ + @mkdir -p ./files/plugins + @mkdir -p ./files/themes + +.PHONY: build lint clean +>>>>>>> Makefile diff --git a/fetcher.py b/fetcher.py new file mode 100755 index 0000000..5ce0b50 --- /dev/null +++ b/fetcher.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python3 + +import os +import shutil +import subprocess +import urllib.request +import zipfile + + +zip_plugins_to_get = { + # please keep these in alphabetical order + '404page', + 'all-in-one-event-calendar', + 'coschedule-by-todaymade', + 'elementor', + 'essential-addons-for-elementor-lite', + 'favicon-by-realfavicongenerator', + 'feedwordpress', + 'fruitful-shortcodes', + 'genesis-columns-advanced', + 'line-break-shortcode', + 'no-category-base-wpml', + 'openid', + 'post-grid', + 'powerpress', + 'redirection', + 'relative-image-urls', + 'rel-publisher', + 'safe-svg', + 'show-current-template', + 'simple-301-redirects', + 'simple-custom-css', + 'social-media-buttons-toolbar', + 'so-widgets-bundle', + 'svg-support', + 'syntaxhighlighter', + 'wordpress-importer', + 'wordpress-seo', + 'wp-font-awesome', + 'wp-lightbox-2', + 'wp-markdown', + 'wp-mastodon-share', + 'wp-polls', + 'wp-statistics', +} + +branch_plugins_to_get = { + # please keep these in alphabetical order + 'launchpad-integration': {'url': 'https://git.launchpad.net/~canonical-sysadmins/wordpress-launchpad-integration/+git/wordpress-launchpad-integration'}, + 'openstack-objectstorage': {'url': 'https://git.launchpad.net/~canonical-sysadmins/wordpress/+git/openstack-objectstorage-k8s'}, + 'teams-integration': {'url': 'https://git.launchpad.net/~canonical-sysadmins/wordpress-teams-integration/+git/wordpress-teams-integration'}, + 'xubuntu-team-members': {'url': 'https://git.launchpad.net/~canonical-sysadmins/wordpress/+git/wp-plugin-xubuntu-team-members'}, +} + +branch_themes_to_get = { + # please keep these in alphabetical order + 'fruitful': {'url': 'https://git.launchpad.net/~canonical-sysadmins/wordpress/+git/wp-theme-fruitful'}, + 'light-wordpress-theme': {'url': 'https://git.launchpad.net/~canonical-sysadmins/ubuntu-community-webthemes/+git/light-wordpress-theme'}, + 'mscom': {'url': 'https://git.launchpad.net/~canonical-sysadmins/wordpress/+git/wp-theme-mscom'}, + 'twentyeleven': {'url': 'https://git.launchpad.net/~canonical-sysadmins/wordpress/+git/wp-theme-twentyeleven'}, + 'ubuntu-cloud-website': {'url': 'https://git.launchpad.net/~canonical-sysadmins/ubuntu-cloud-website/+git/ubuntu-cloud-website'}, + 'ubuntu-community': {'url': 'https://git.launchpad.net/~canonical-sysadmins/wordpress/+git/wp-theme-ubuntu-community'}, + 'ubuntu-community-wordpress-theme': {'url': 'https://git.launchpad.net/~canonical-sysadmins/ubuntu-community-wordpress-theme/+git/ubuntu-community-wordpress-theme'}, + 'ubuntu-fi-new': {'url': 'https://git.launchpad.net/~canonical-sysadmins/wordpress/+git/wp-theme-ubuntu-fi'}, + 'ubuntu-light': {'url': 'https://git.launchpad.net/~canonical-sysadmins/wordpress/+git/wp-theme-ubuntu-light'}, + 'ubuntustudio-wp': {'url': 'https://git.launchpad.net/~canonical-sysadmins/wordpress/+git/wp-theme-ubuntustudio-wp'}, + 'wordpress_launchpad': {'url': 'https://git.launchpad.net/~canonical-sysadmins/wordpress/+git/wp-theme-launchpad'}, + 'xubuntu-theme': {'url': 'https://git.launchpad.net/~canonical-sysadmins/wordpress/+git/wp-theme-xubuntu-website'}, +} + + +def get_plugins(zip_plugins, branch_plugins): + total_zips = len(zip_plugins) + current_zip = 0 + for zip_plugin in zip_plugins: + current_zip = current_zip + 1 + print('Downloading {} of {} zipped plugins: {} ...'.format(current_zip, total_zips, zip_plugin)) + url = 'https://downloads.wordpress.org/plugin/{}.latest-stable.zip'.format(zip_plugin) + file_name = os.path.join(os.getcwd(), 'files/plugins', os.path.basename(url)) + with urllib.request.urlopen(url) as response, open(file_name, 'wb') as out_file: + shutil.copyfileobj(response, out_file) + with zipfile.ZipFile(file_name, 'r') as zip_ref: + zip_ref.extractall(os.path.join(os.getcwd(), 'files/plugins')) + os.remove(file_name) + + total_branches = len(branch_plugins) + current_branch = 0 + for branch_plugin in branch_plugins: + current_branch = current_branch + 1 + print('Downloading {} of {} branched plugins: {} ...'.format(current_branch, total_branches, branch_plugin)) + url = branch_plugins[branch_plugin].get('url') + basename = os.path.basename(url) + if basename.startswith('lp:'): + basename = basename[3:] + if basename.startswith('wp-plugin-'): + basename = basename[10:] + dest = os.path.join(os.getcwd(), 'files/plugins', basename) + if url.startswith('lp:'): + cmd = ['bzr', 'branch', url, dest] + elif url.startswith('https://git'): + cmd = ['git', 'clone', url, dest] + else: + print("ERROR: Don't know how to clone {}".format(url)) + exit(1) + _ = subprocess.check_output(cmd, universal_newlines=True, stderr=subprocess.STDOUT) + + +def get_themes(branch_themes): + total_branches = len(branch_themes) + current_branch = 0 + for branch_theme in branch_themes: + current_branch = current_branch + 1 + print('Downloading {} of {} branched themes: {} ...'.format(current_branch, total_branches, branch_theme)) + url = branch_themes[branch_theme].get('url') + basename = os.path.basename(url) + if basename.startswith('lp:'): + basename = basename[3:] + if basename.startswith('wp-theme-'): + basename = basename[9:] + dest = os.path.join(os.getcwd(), 'files/themes/', basename) + if url.startswith('lp:'): + cmd = ['bzr', 'branch', url, dest] + elif url.startswith('https://git'): + cmd = ['git', 'clone', url, dest] + else: + print("ERROR: Don't know how to clone {}".format(url)) + exit(1) + _ = subprocess.check_output(cmd, universal_newlines=True, stderr=subprocess.STDOUT) + + +if __name__ == '__main__': + get_plugins(zip_plugins_to_get, branch_plugins_to_get) + get_themes(branch_themes_to_get) diff --git a/files/_add_option.php b/files/_add_option.php new file mode 100644 index 0000000..cbfe8a8 --- /dev/null +++ b/files/_add_option.php @@ -0,0 +1,11 @@ +<?php + +# PHP cli helper which adds new option to wp_settings table +# +# Example use: +# php ./_add_option.php akismet_strictness 0 + +@include "wp-config.php"; +@include_once "wp-includes/option.php"; +@include_once "wp-includes/functions.php"; +add_option($argv[1], maybe_unserialize($argv[2])); diff --git a/files/_enable_plugin.php b/files/_enable_plugin.php new file mode 100644 index 0000000..11ed3e7 --- /dev/null +++ b/files/_enable_plugin.php @@ -0,0 +1,14 @@ +<?php + +# PHP cli helper which enables a plugin. Plugin name is in +# format returned by _list_inactive_plugins.php helper +# +# Example use: +# php ./_enable_plugin.php akismet/akismet.php openid/openid.php + +@include "wp-config.php"; +@include_once "wp-admin/includes/plugin.php"; +$result = activate_plugins(array_slice($argv, 1)); +if ( is_wp_error( $result ) ) { + throw new Exception($result); +} diff --git a/files/_get_option.php b/files/_get_option.php new file mode 100644 index 0000000..4168301 --- /dev/null +++ b/files/_get_option.php @@ -0,0 +1,15 @@ +<?php + +# PHP cli helper which returns option value if present +# +# Example use: +# php ./_get_option.php akismet_strictness + +@include "wp-config.php"; +@include_once "wp-includes/option.php"; +@include_once "/usr/share/php/Symfony/Component/Yaml/autoload.php"; + +use Symfony\Component\Yaml\Yaml; + +$value = get_option($argv[1]); +print Yaml::dump($value); diff --git a/files/docker-entrypoint.sh b/files/docker-entrypoint.sh new file mode 100644 index 0000000..4acb037 --- /dev/null +++ b/files/docker-entrypoint.sh @@ -0,0 +1,19 @@ +#!/bin/bash +set -eu + +sed -i -e "s/%%%WORDPRESS_DB_HOST%%%/$WORDPRESS_DB_HOST/" /var/www/html/wp-info.php +sed -i -e "s/%%%WORDPRESS_DB_NAME%%%/$WORDPRESS_DB_NAME/" /var/www/html/wp-info.php +sed -i -e "s/%%%WORDPRESS_DB_USER%%%/$WORDPRESS_DB_USER/" /var/www/html/wp-info.php +sed -i -e "s/%%%WORDPRESS_DB_PASSWORD%%%/$WORDPRESS_DB_PASSWORD/" /var/www/html/wp-info.php + +for key in AUTH_KEY SECURE_AUTH_KEY LOGGED_IN_KEY NONCE_KEY AUTH_SALT SECURE_AUTH_SALT LOGGED_IN_SALT NONCE_SALT; +do + sed -i -e "s/%%%${key}%%%/$(printenv ${key})/" /var/www/html/wp-info.php +done + +nohup bash -c "/srv/wordpress-helpers/plugin_handler.py &" + +sed -i 's/max_execution_time = 30/max_execution_time = 300/' /etc/php/7.2/apache2/php.ini +sed -i 's/upload_max_filesize = 2M/upload_max_filesize = 10M/' /etc/php/7.2/apache2/php.ini + +exec "$@" diff --git a/files/docker-php.conf b/files/docker-php.conf new file mode 100644 index 0000000..a6091d1 --- /dev/null +++ b/files/docker-php.conf @@ -0,0 +1,27 @@ +PassEnv SWIFT_URL + +<FilesMatch \.php$> + SetHandler application/x-httpd-php +</FilesMatch> + +<Location "/wp-admin"> + Header Set Cache-Control "max-age=0, no-store" +</Location> + +DirectoryIndex disabled +DirectoryIndex index.php index.html + +<Directory /var/www/> + Options -Indexes + AllowOverride All + RewriteEngine On + RewriteBase / + RewriteRule ^index\.php$ - [L] + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_FILENAME} !-d + RewriteRule . /index.php [L] +</Directory> + +ProxyPass /wp-content/uploads/ ${SWIFT_URL} +ProxyPassReverse /wp-content/uploads/ ${SWIFT_URL} +Timeout 300 diff --git a/files/plugin_handler.py b/files/plugin_handler.py new file mode 100644 index 0000000..94403ec --- /dev/null +++ b/files/plugin_handler.py @@ -0,0 +1,152 @@ +#!/usr/bin/python3 + +import logging +import os +import subprocess +import urllib.request +from time import sleep +from yaml import safe_load + +helpers_path = "/srv/wordpress-helpers" +install_path = "/var/www/html" + + +def call_php_helper(helper, stdin="", *args): + path = os.path.join(helpers_path, helper) + cmd = ["php", path] + cmd.extend([str(arg) for arg in args]) + logging.info(cmd) + process = subprocess.Popen( + cmd, + cwd=install_path, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + ) + return process.communicate(stdin)[0] # spit back stdout+stderr combined + + +def enable_plugin(*plugins): + logging.info("Enabling plugins: {}".format(plugins)) + logging.info(call_php_helper("_enable_plugin.php", "", *plugins)) + + +def get_option(key): + value = call_php_helper("_get_option.php", "", key) + return safe_load(value) + + +def add_option(key, value): + # Ensure we don't overwrite settings + if not get_option(key): + logging.info("Adding option: {}".format(key)) + call_php_helper("_add_option.php", "", key, value) + else: + logging.info('Option "{}" already in place, skipping.'.format(key)) + + +def encode_team_map(team_map): + # example: site-sysadmins=administrator,site-editors=editor,site-executives=editor + team_map_lines = [] + i = 0 + team_map_lines.append("a:{}:{{".format(len(team_map.split(",")))) + for mapping in team_map.split(","): + i = i + 1 + team, role = mapping.split("=", 2) + team_map_lines.append("i:{};".format(i)) + team_map_lines.append('O:8:"stdClass":4:{') + team_map_lines.append('s:2:"id";') + team_map_lines.append("i:{};".format(i)) + team_map_lines.append('s:4:"team";') + team_map_lines.append('s:{}:"{}";'.format(len(team), team)) + team_map_lines.append('s:4:"role";') + team_map_lines.append('s:{}:"{}";'.format(len(role), role)) + team_map_lines.append('s:6:"server";') + team_map_lines.append('s:1:"0";') + team_map_lines.append("}") + team_map_lines.append("}") + + return "".join(team_map_lines) + + +def enable_akismet(key): + enable_plugin("akismet/akismet.php") + add_option("akismet_strictness", "0") + add_option("akismet_show_user_comments_approved", "0") + add_option("wordpress_api_key", key) + + +def enable_openid(team_map): + encoded_team_map = encode_team_map(team_map) + enable_plugin("openid/openid.php") + add_option("openid_required_for_registration", "1") + add_option("openid_teams_trust_list", encoded_team_map) + + +def enable_swift(swift_config): + enable_plugin("openstack-objectstorage/objectstorage.php") + for k, v in swift_config.items(): + add_option("object_storage_{}".format(k), v) + + +def configure_wordpress(): + url = "http://localhost" + sleep_time = 10 + total_sleep_time = 0 + max_sleep_time = 600 + success = False + while success is not True: + if total_sleep_time > max_sleep_time: + return False + try: + response = urllib.request.urlopen(url, timeout=sleep_time) + except Exception: + logging.info("Waiting for Wordpress to accept connections") + sleep(sleep_time) + total_sleep_time = total_sleep_time + sleep_time + else: + if response.status == 200: + success = True + else: + logging.info( + "Waiting for Wordpress to return HTTP 200 (got {})".format( + response.status + ) + ) + sleep(sleep_time) + return True + + +if __name__ == "__main__": + logger = logging.getLogger(__name__) + logging.basicConfig( + filename="/var/log/wordpress-plugin-handler.log", level=logging.DEBUG + ) + + if configure_wordpress(): + # create the file to satisfy the readinessProbe + open(os.path.join(helpers_path, '.ready'), 'a').close() + + key = os.getenv("WP_PLUGIN_AKISMET_KEY") + if key: + enable_akismet(key) + + team_map = os.getenv("WP_PLUGIN_OPENID_TEAM_MAP") + if team_map: + enable_openid(team_map) + + swift_url = os.getenv("SWIFT_URL") + if swift_url: + swift_config = {} + swift_config['url'] = swift_url + swift_config['auth_url'] = os.getenv("SWIFT_AUTH_URL") + swift_config['bucket'] = os.getenv("SWIFT_BUCKET") + swift_config['password'] = os.getenv("SWIFT_PASSWORD") + swift_config['prefix'] = os.getenv("SWIFT_PREFIX") + swift_config['region'] = os.getenv("SWIFT_REGION") + swift_config['tenant'] = os.getenv("SWIFT_TENANT") + swift_config['username'] = os.getenv("SWIFT_USERNAME") + swift_config['copy_to_swift'] = os.getenv("SWIFT_COPY_TO_SWIFT") + swift_config['serve_from_swift'] = os.getenv("SWIFT_SERVE_FROM_SWIFT") + swift_config['remove_local_file'] = os.getenv("SWIFT_REMOVE_LOCAL_FILE") + enable_swift(swift_config) diff --git a/files/ready.sh b/files/ready.sh new file mode 100644 index 0000000..a676bc2 --- /dev/null +++ b/files/ready.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +READY=/srv/wordpress-helpers/.ready + +# This script is designed to be called by the Kubernetes +# readinessProbe. If the WP plugins haven't been enabled +# which we know due to the $READY file not existing then +# return a failure, replace the shell with whatever curl +# returns for checking that the website is alive. +if [ -f "$READY" ]; then + exec /usr/bin/curl --silent http://localhost +fi + +exit 1 diff --git a/files/wp-config.php b/files/wp-config.php new file mode 100644 index 0000000..b47b161 --- /dev/null +++ b/files/wp-config.php @@ -0,0 +1,52 @@ +<?php +# +# " " +# mmm m m mmm m m +# # # # # # # +# # # # # # # +# # "mm"# # "mm"# +# # # +# "" "" +# This file is managed by Juju. Do not make local changes. +# + +/* That's all, stop editing! Happy blogging. */ + +/** Enable container debug level logging. **/ +if ( getenv("WORDPRESS_DEBUG") ) { + define( 'WP_DEBUG', true ); + define( 'WP_DEBUG_DISPLAY', false ); + define( 'WP_DEBUG_LOG', '/dev/stderr' ); +} + +/** Fixes for mixed content when WordPress is behind nginx TLS reverse proxy. + * https://ahenriksson.com/2020/01/27/how-to-set-up-wordpress-behind-a-reverse-proxy-when-using-nginx/ + * */ +define('FORCE_SSL_ADMIN', true); +if ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') + $_SERVER['HTTPS']='on'; + +/** Absolute path to the WordPress directory. */ +if ( !defined('ABSPATH') ) + define('ABSPATH', dirname(__FILE__) . '/'); + +/** Pull in the config information */ +require_once(ABSPATH . 'wp-info.php'); + +/** Sets up WordPress vars and included files. */ +require_once(ABSPATH . 'wp-settings.php'); + +/** Prevent wordpress from attempting to update and make external requests. + * + * Our firewalls do not allow WordPress to communicate externally to wordpress.org + * for auto-updates, this causes our kubernetes pods to timeout during initial configuration, + * preventing the site from ever becoming available. + * */ +define( 'AUTOMATIC_UPDATER_DISABLED', true ); +define( 'WP_AUTO_UPDATE_CORE', false ); + +$http_host = $_SERVER['HTTP_HOST']; +define('WP_HOME',"https://$http_host"); +define('WP_SITEURL',"https://$http_host"); + +remove_filter('template_redirect', 'redirect_canonical'); diff --git a/files/wp-info.php b/files/wp-info.php new file mode 100644 index 0000000..5a891a2 --- /dev/null +++ b/files/wp-info.php @@ -0,0 +1,53 @@ +<?php +# +# " " +# mmm m m mmm m m +# # # # # # # +# # # # # # # +# # "mm"# # "mm"# +# # # +# "" "" +# This file is managed by Juju. Do not make local changes. +# + +// We have to cheat a little because frontend service can terminate SSL +// If it does it should set X-Edge-Https header to "on" to tell us original +// request came on https + +if (!empty($_SERVER['HTTP_X_EDGE_HTTPS']) && 'off' != $_SERVER['HTTP_X_EDGE_HTTPS']) { + $_SERVER['HTTPS'] = 'on'; +} + +if (!empty($_SERVER['HTTPS']) && 'off' != $_SERVER['HTTPS']) { + define('WP_PLUGIN_URL', 'https://' . $_SERVER['HTTP_HOST'] . '/wp-content/plugins'); + define('WP_CONTENT_URL', 'https://' . $_SERVER['HTTP_HOST'] . '/wp-content'); + define('WP_SITEURL', 'https://' . $_SERVER['HTTP_HOST']); + define('WP_URL', 'https://' . $_SERVER['HTTP_HOST']); + define('WP_HOME', 'https://' . $_SERVER['HTTP_HOST']); +} +else { + define('WP_PLUGIN_URL', 'http://' . $_SERVER['HTTP_HOST'] . '/wp-content/plugins'); + define('WP_CONTENT_URL', 'http://' . $_SERVER['HTTP_HOST'] . '/wp-content'); + define('WP_SITEURL', 'http://' . $_SERVER['HTTP_HOST']); + define('WP_URL', 'http://' . $_SERVER['HTTP_HOST']); + define('WP_HOME', 'http://' . $_SERVER['HTTP_HOST']); +} + +define('DB_NAME', '%%%WORDPRESS_DB_NAME%%%'); +define('DB_USER', '%%%WORDPRESS_DB_USER%%%'); +define('DB_HOST', '%%%WORDPRESS_DB_HOST%%%'); + +define('DB_PASSWORD', '%%%WORDPRESS_DB_PASSWORD%%%'); + +define('WP_CACHE', true); + +define('AUTH_KEY', '%%%AUTH_KEY%%%'); +define('SECURE_AUTH_KEY', '%%%SECURE_AUTH_KEY%%%'); +define('LOGGED_IN_KEY', '%%%LOGGED_IN_KEY%%%'); +define('NONCE_KEY', '%%%NONCE_KEY%%%'); +define('AUTH_SALT', '%%%AUTH_SALT%%%'); +define('SECURE_AUTH_SALT', '%%%SECURE_AUTH_SALT%%%'); +define('LOGGED_IN_SALT', '%%%LOGGED_IN_SALT%%%'); +define('NONCE_SALT', '%%%NONCE_SALT%%%'); + +$table_prefix = 'wp_'; diff --git a/tests/unit/requirements.txt b/tests/unit/requirements.txt index 460a692..254ba8a 100644 --- a/tests/unit/requirements.txt +++ b/tests/unit/requirements.txt @@ -1,3 +1,4 @@ +<<<<<<< tests/unit/requirements.txt requests charmhelpers charms.reactive @@ -7,3 +8,8 @@ mock pytest pytest-cov python2-secrets +======= +pytest +pytest-cov +PyYAML +>>>>>>> tests/unit/requirements.txt diff --git a/tests/unit/test_plugin_hander.py b/tests/unit/test_plugin_hander.py new file mode 100644 index 0000000..86f353b --- /dev/null +++ b/tests/unit/test_plugin_hander.py @@ -0,0 +1,37 @@ +import os +import sys +import unittest +from unittest import mock + +sys.path.append(os.path.join("..", "..", os.path.dirname(__file__))) +from files import plugin_handler # NOQA: E402 + + +class testWrapper(unittest.TestCase): + def setUp(self): + self.maxDiff = None + + @mock.patch("files.plugin_handler.logging") + def test_team_mapper(self, foo): + given = ",".join( + [ + "canonical-sysadmins=administrator", + "canonical-website-editors=editor", + "canonical-website-admins=administrator", + "launchpad=editor", + ] + ) + want = "".join( + [ + """a:4:{i:1;O:8:"stdClass":4:{s:2:"id";i:1;s:4:"team";s:19:"canonical-sysadmins";""", + """s:4:"role";s:13:"administrator";s:6:"server";s:1:"0";}""", + """i:2;O:8:"stdClass":4:{s:2:"id";i:2;s:4:"team";s:25:"canonical-website-editors";""", + """s:4:"role";s:6:"editor";s:6:"server";s:1:"0";}""", + """i:3;O:8:"stdClass":4:{s:2:"id";i:3;s:4:"team";s:24:"canonical-website-admins";""", + """s:4:"role";s:13:"administrator";s:6:"server";s:1:"0";}""", + """i:4;O:8:"stdClass":4:{s:2:"id";i:4;s:4:"team";s:9:"launchpad";""", + """s:4:"role";s:6:"editor";s:6:"server";s:1:"0";}}""", + ] + ) + got = plugin_handler.encode_team_map(given) + self.assertEqual(got, want) diff --git a/tox.ini b/tox.ini index 6b43ea1..8623f88 100644 --- a/tox.ini +++ b/tox.ini @@ -1,13 +1,19 @@ [tox] skipsdist=True +<<<<<<< tox.ini envlist = unit, integration skip_missing_interpreters = True toxworkdir=/tmp/charm-k8s-wordpress/.tox +======= +envlist = build +skip_missing_interpreters = True +>>>>>>> tox.ini [testenv] basepython = python3 setenv = PYTHONPATH = . +<<<<<<< tox.ini passenv = WORKSPACE @@ -43,11 +49,40 @@ deps = black commands = flake8 src/ tests/ deps = flake8 +======= + +[testenv:black] +commands = {envbindir}/black --skip-string-normalization --line-length=120 . +deps = black + +[testenv:lint] +commands = {envbindir}/flake8 +deps = flake8 + +[testenv:fetch] +commands = ./fetcher.py +passenv = HTTP_PROXY HTTPS_PROXY +setenv = + BZR_HOME = /tmp + +[testenv:unit] +commands = + pytest {posargs:-v --cov=. --cov-report=term-missing --cov-branch} +deps = -r{toxinidir}/tests/unit/requirements.txt +setenv = + PYTHONPATH={toxinidir}/lib + TZ=UTC + +>>>>>>> tox.ini [flake8] exclude = .git, __pycache__, .tox, +<<<<<<< tox.ini ignore = E402 +======= + files/ +>>>>>>> tox.ini max-line-length = 120 max-complexity = 10
-- Mailing list: https://launchpad.net/~wordpress-charmers Post to : wordpress-charmers@lists.launchpad.net Unsubscribe : https://launchpad.net/~wordpress-charmers More help : https://help.launchpad.net/ListHelp