wordpress-charmers team mailing list archive
-
wordpress-charmers team
-
Mailing list archive
-
Message #00726
[Merge] ~tcuthbert/charm-k8s-wordpress:xubuntu-container-fixes into charm-k8s-wordpress:master
Thomas Cuthbert has proposed merging ~tcuthbert/charm-k8s-wordpress:xubuntu-container-fixes into charm-k8s-wordpress:master.
Requested reviews:
Wordpress Charmers (wordpress-charmers)
For more details, see:
https://code.launchpad.net/~tcuthbert/charm-k8s-wordpress/+git/charm-k8s-wordpress-1/+merge/403642
--
Your team Wordpress Charmers is requested to review the proposed merge of ~tcuthbert/charm-k8s-wordpress:xubuntu-container-fixes into charm-k8s-wordpress:master.
diff --git a/Dockerfile b/Dockerfile
index 21e3b76..5f50716 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,11 +1,5 @@
ARG DIST_RELEASE
-FROM ubuntu:${DIST_RELEASE}
-ARG DIST_RELEASE
-ARG VERSION
-
-LABEL maintainer="wordpress-charmers@xxxxxxxxxxxxxxxxxxx"
-# Used by Launchpad OCI Recipe to tag version
-LABEL org.label-schema.version=${VERSION:-5.6}
+FROM ubuntu:${DIST_RELEASE} as base
# HTTPS_PROXY used when we RUN curl to download Wordpress itself
ARG BUILD_DATE
@@ -42,6 +36,7 @@ RUN apt-get update && apt-get -y dist-upgrade \
python3 \
python3-yaml \
ssl-cert \
+ wget \
&& 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 \
@@ -62,8 +57,23 @@ RUN a2enconf docker-php \
&& a2enmod rewrite \
&& a2enmod ssl
+
+FROM base as plugins
+
+# Download themes and plugins. This will eventually be separated into new container.
+COPY ./image-builder/src/fetcher.py /
+WORKDIR /var/www/html/wp-content/
+RUN mkdir themes plugins && /fetcher.py
+VOLUME /var/www/html/wp-content
+
+FROM base As install
+ARG VERSION
+
+# TODO: replace downloading the source wordpress code with copying it from the upstream wordpress container,
+# which should speed builds up:
+# COPY --from=wordpress-${VERSION}:fpm /usr/src/wordpress /usr/src/wordpress
# 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/wordpress-${VERSION}.tar.gz" \
+RUN wget -O wordpress.tar.gz -t 3 -r "https://wordpress.org/wordpress-${VERSION}.tar.gz" \
&& tar -xzf wordpress.tar.gz -C /usr/src/ \
&& rm wordpress.tar.gz \
&& chown -R www-data:www-data /usr/src/wordpress \
@@ -71,17 +81,9 @@ RUN curl -o wordpress.tar.gz -fSL "https://wordpress.org/wordpress-${VERSION}.ta
&& mv /usr/src/wordpress /var/www/html
COPY ./image-builder/files/ /files/
-COPY ./image-builder/src/fetcher.py .
-RUN mkdir -p /files/themes /files/plugins
-RUN ./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
@@ -97,10 +99,19 @@ 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
+FROM install as wordpress
+ARG VERSION
+
+LABEL maintainer="wordpress-charmers@xxxxxxxxxxxxxxxxxxx"
+# Used by Launchpad OCI Recipe to tag version
+LABEL org.label-schema.version=${VERSION:-5.7}
# Port 80 only, TLS will terminate elsewhere
EXPOSE 80
+# Copy plugins from the plugin stage into the WordPress content directory.
+COPY ./image-builder/src/fetcher.py /
+COPY --chown=www-data:www-data --from=plugins /var/www/html/wp-content/plugins/ /var/www/html/wp-content/plugins/
+COPY --chown=www-data:www-data --from=plugins /var/www/html/wp-content/themes/ /var/www/html/wp-content/themes/
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
CMD apachectl -D FOREGROUND
diff --git a/image-builder/files/docker-entrypoint.sh b/image-builder/files/docker-entrypoint.sh
index 545d54e..42caf39 100644
--- a/image-builder/files/docker-entrypoint.sh
+++ b/image-builder/files/docker-entrypoint.sh
@@ -14,6 +14,15 @@ done
# If we have passed in SWIFT_URL, then append swift proxy config.
[ -z "${SWIFT_URL-}" ] || a2enconf docker-php-swift-proxy
+# TODO: this will eventually be called directly by the charm.
+(
+ cd /tmp
+ /fetcher.py
+ find /tmp -type f \( -path '/tmp/plugins/*' -o -path '/tmp/themes/*' \) -printf "%p\0/var/www/html/wp-content/%P\0" |
+ xargs -rn2 -0 install -DT && rm -fr /tmp/* &&
+ rm -fr /tmp/*
+)
+
nohup bash -c "/srv/wordpress-helpers/plugin_handler.py &"
# Match against either php 7.2 (bionic) or 7.4 (focal).
diff --git a/image-builder/src/fetcher.py b/image-builder/src/fetcher.py
index b7085f2..7d77fd2 100755
--- a/image-builder/src/fetcher.py
+++ b/image-builder/src/fetcher.py
@@ -3,8 +3,12 @@
import os
import shutil
import subprocess
+import sys
import urllib.request
import zipfile
+from typing import Mapping, List
+from urllib.parse import urlparse
+from yaml import safe_load
zip_plugins_to_get = {
@@ -98,11 +102,11 @@ def get_plugins(zip_plugins, branch_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))
+ file_name = os.path.join(os.getcwd(), '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'))
+ zip_ref.extractall(os.path.join(os.getcwd(), 'plugins'))
os.remove(file_name)
total_branches = len(branch_plugins)
@@ -116,7 +120,7 @@ def get_plugins(zip_plugins, branch_plugins):
basename = basename[3:]
if basename.startswith('wp-plugin-'):
basename = basename[10:]
- dest = os.path.join(os.getcwd(), 'files/plugins', basename)
+ dest = os.path.join(os.getcwd(), 'plugins', basename)
if url.startswith('lp:'):
cmd = ['bzr', 'branch', url, dest]
elif url.startswith('https://git'):
@@ -139,7 +143,7 @@ def get_themes(branch_themes):
basename = basename[3:]
if basename.startswith('wp-theme-'):
basename = basename[9:]
- dest = os.path.join(os.getcwd(), 'files/themes/', basename)
+ dest = os.path.join(os.getcwd(), 'themes/', basename)
if url.startswith('lp:'):
cmd = ['bzr', 'branch', url, dest]
elif url.startswith('https://git'):
@@ -150,6 +154,112 @@ def get_themes(branch_themes):
_ = subprocess.check_output(cmd, universal_newlines=True, stderr=subprocess.STDOUT)
-if __name__ == '__main__':
+class Plugin:
+ name: str
+ _protocol: str
+ _url: str
+ _owner = "www-data"
+ _group = "www-data"
+
+ def __init__(self, name: str, url: str):
+ self.name = name
+ self.url = url
+
+ def __str__(self) -> str:
+ return self.name
+
+ def __repr__(self) -> str:
+ kwargs = {"name": self.name, "url": self.url}
+ return "<Plugin>(name={name}, url={url})".format(**kwargs)
+
+ @property
+ def url(self):
+ return self._url
+
+ @url.setter
+ def url(self, url: str):
+ u = urlparse(url)
+ self._url = u.geturl()
+ self._protocol = u.scheme.split("+")[0]
+ self._protocol = self._protocol.replace("https", "git")
+
+ def is_available(self):
+ print("NOT IMPLEMENTED")
+
+ def is_bzr(self):
+ return self._protocol == "lp"
+
+ def is_git(self):
+ return self._protocol == "git"
+
+ def sync(self, dest_dir: str):
+ plugin_path = os.path.join(dest_dir, self.name)
+ try:
+ self.__call_sync(plugin_path)
+ except subprocess.CalledProcessError as ce:
+ shutil.rmtree(plugin_path)
+ print("ERROR: {0}: failed to sync plugin: {1}, cleaning up plugin dir: {2}".format(str(ce), self,
+ plugin_path))
+ else:
+ self.__chown_path(plugin_path)
+
+ def __build_cmd(self, dest_dir: str) -> List[str]:
+ cmds = {
+ "git": ["git", "clone", self.url, dest_dir],
+ "lp": ["bzr", "branch", self.url, dest_dir],
+ }
+ return cmds[self._protocol]
+
+ def __call_sync(self, plugin_path: str, verbose=True):
+ subprocess_kwargs = {}
+ subprocess_kwargs["check"] = True
+ subprocess_kwargs["universal_newlines"] = True
+ if verbose:
+ subprocess_kwargs["stderr"] = subprocess.STDOUT
+
+ dirname = os.path.dirname(plugin_path)
+ if not os.path.exists(dirname):
+ self.__make_path(dirname)
+ print("DEBUG: syncing plugin at path: {0}".format(plugin_path))
+ rv = subprocess.run(self.__build_cmd(plugin_path), **subprocess_kwargs)
+ return rv.returncode
+
+ def __chown_path(self, path: str):
+ for dirpath, _, filenames in os.walk(path):
+ shutil.chown(dirpath, "www-data", "www-data")
+ for filename in filenames:
+ shutil.chown(os.path.join(dirpath, filename), self._owner, self._group)
+
+ def __make_path(self, path: str):
+ print("DEBUG: creating directory: {0}".format(path))
+ os.makedirs(path, mode=0o755)
+
+
+def sync_additional_plugins(additional_plugins: Mapping[str, str]):
+ """
+ Sync any additional WordPress plugins specified from the Container
+ environment variable: WORDPRESS_ADDITIONAL_PLUGINS.
+
+ WORDPRESS_ADDITIONAL_PLUGINS must be a valid YAML formatted map string.
+ """
+ dest_path = os.path.join(os.getcwd(), "plugins")
+ total_plugins = len(additional_plugins)
+ count = 0
+ for name, url in additional_plugins.items():
+ count += 1
+ plugin = Plugin(name, url)
+ print("Syncing {0} of {1} WordPress plugins: {2} ...".format(count, total_plugins, plugin))
+ plugin.sync(dest_path)
+
+
+if __name__ == "__main__":
+ additional_plugins = os.environ.get("WORDPRESS_ADDITIONAL_PLUGINS")
+ if additional_plugins:
+ plugins = safe_load(additional_plugins.encode("utf-8"))
+ sync_additional_plugins(plugins)
+ # TODO: Script should have command-line flags instead of this.
+ if any([e for e in os.environ.keys() if e.startswith("WORDPRESS")]):
+ print("DEBUG: we are running inside a container, no need to sync base plugins")
+ sys.exit(0)
get_plugins(zip_plugins_to_get, branch_plugins_to_get)
get_themes(branch_themes_to_get)
diff --git a/image-builder/tests/unit/test_fetcher.py b/image-builder/tests/unit/test_fetcher.py
new file mode 100644
index 0000000..edced66
--- /dev/null
+++ b/image-builder/tests/unit/test_fetcher.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python3
+import unittest
+from unittest.mock import patch
+
+from fetcher import Plugin
+from fetcher import sync_additional_plugins
+
+
+class TestPlugin(unittest.TestCase):
+ test_name = "testPlugin"
+ test_url = "lp:~testUser/testProject/testBranch"
+
+ def setUp(self):
+ test_name = self.test_name
+ test_url = self.test_url
+ self.plugin = Plugin(test_name, test_url)
+
+ def test__init__(self):
+ plugin = Plugin(TestPlugin.test_name, TestPlugin.test_url)
+ name = plugin.name
+ protocol = plugin._protocol
+ url = plugin.url
+ self.assertEqual(name, TestPlugin.test_name)
+ self.assertEqual(protocol, TestPlugin.test_url.split(":")[0])
+ self.assertEqual(url, TestPlugin.test_url)
+
+ def test_is_available(self):
+ self.plugin.is_available()
+
+ def test_is_bzr(self):
+ self.assertTrue(self.plugin.is_bzr())
+
+ def test_is_git(self):
+ self.assertFalse(self.plugin.is_git())
+
+ @patch.object(Plugin, "_Plugin__make_dest")
+ @patch.object(Plugin, "_Plugin__call_sync")
+ def test_sync(self, mock_call_sync, mock_make_dest):
+
+ mock_call_sync.return_value = None
+ self.plugin.sync("test/path")
+
+ assert mock_call_sync.called
+ assert mock_make_dest.called
+
+ mock_call_sync.return_value = True
+ with self.assertRaises(RuntimeError) as cm:
+ self.plugin.sync("test/path")
+ self.assertTrue("failed to sync plugin" in str(cm.exception))
diff --git a/tox.ini b/tox.ini
index 0736115..9abc7b0 100644
--- a/tox.ini
+++ b/tox.ini
@@ -14,12 +14,12 @@ passenv =
[testenv:unit]
commands =
- pytest --ignore image-builder --ignore {toxinidir}/tests/integration \
+ pytest --ignore image-builder/files --ignore {toxinidir}/tests/integration \
{posargs:-v --cov=src --cov-report=term-missing --cov-branch}
deps = -r{toxinidir}/tests/unit/requirements.txt
-r{toxinidir}/requirements.txt
setenv =
- PYTHONPATH={toxinidir}/src:{toxinidir}/build/lib:{toxinidir}/build/venv
+ PYTHONPATH={toxinidir}/src:{toxinidir}/build/lib:{toxinidir}/build/venv:{toxinidir}/image-builder/src:{toxinidir}/image-builder/files
TZ=UTC
[testenv:integration]
Follow ups
-
[Merge] ~tcuthbert/charm-k8s-wordpress:xubuntu-container-fixes into charm-k8s-wordpress:master
From: noreply, 2021-06-03
-
Re: [Merge] ~tcuthbert/charm-k8s-wordpress:xubuntu-container-fixes into charm-k8s-wordpress:master
From: Canonical IS Mergebot, 2021-06-03
-
[Merge] ~tcuthbert/charm-k8s-wordpress:xubuntu-container-fixes into charm-k8s-wordpress:master
From: Thomas Cuthbert, 2021-06-03
-
Re: [Merge] ~tcuthbert/charm-k8s-wordpress:xubuntu-container-fixes into charm-k8s-wordpress:master
From: Tom Haddon, 2021-06-03
-
Re: [Merge] ~tcuthbert/charm-k8s-wordpress:xubuntu-container-fixes into charm-k8s-wordpress:master
From: 🤖 prod-jenkaas-is, 2021-06-03
-
[Merge] ~tcuthbert/charm-k8s-wordpress:xubuntu-container-fixes into charm-k8s-wordpress:master
From: Thomas Cuthbert, 2021-06-03
-
Re: [Merge] ~tcuthbert/charm-k8s-wordpress:xubuntu-container-fixes into charm-k8s-wordpress:master
From: 🤖 prod-jenkaas-is, 2021-06-02
-
Re: [Merge] ~tcuthbert/charm-k8s-wordpress:xubuntu-container-fixes into charm-k8s-wordpress:master
From: 🤖 prod-jenkaas-is, 2021-06-02
-
Re: [Merge] ~tcuthbert/charm-k8s-wordpress:xubuntu-container-fixes into charm-k8s-wordpress:master
From: 🤖 prod-jenkaas-is, 2021-06-02
-
Re: [Merge] ~tcuthbert/charm-k8s-wordpress:xubuntu-container-fixes into charm-k8s-wordpress:master
From: 🤖 prod-jenkaas-is, 2021-06-02
-
Re: [Merge] ~tcuthbert/charm-k8s-wordpress:xubuntu-container-fixes into charm-k8s-wordpress:master
From: 🤖 prod-jenkaas-is, 2021-06-02
-
Re: [Merge] ~tcuthbert/charm-k8s-wordpress:xubuntu-container-fixes into charm-k8s-wordpress:master
From: Canonical IS Mergebot, 2021-06-02
-
Re: [Merge] ~tcuthbert/charm-k8s-wordpress:xubuntu-container-fixes into charm-k8s-wordpress:master
From: Canonical IS Mergebot, 2021-06-02
-
Re: [Merge] ~tcuthbert/charm-k8s-wordpress:xubuntu-container-fixes into charm-k8s-wordpress:master
From: 🤖 prod-jenkaas-is, 2021-06-02