django-orchestra/orchestra/contrib/saas/backends/wordpressmu.py

226 lines
9.0 KiB
Python
Raw Normal View History

2015-03-23 15:36:51 +00:00
import re
2015-10-08 13:54:39 +00:00
import sys
import textwrap
from urllib.parse import urlparse
2015-03-23 15:36:51 +00:00
import requests
from django.utils.translation import ugettext_lazy as _
2015-04-05 10:46:24 +00:00
from orchestra.contrib.orchestration import ServiceController
2015-03-23 15:36:51 +00:00
from . import ApacheTrafficByHost
2015-03-23 15:36:51 +00:00
from .. import settings
2016-03-08 10:16:49 +00:00
class WordpressMuController(ServiceController):
2015-04-24 11:39:20 +00:00
"""
Creates a wordpress site on a WordPress MultiSite installation.
You should point it to the database server
2015-04-24 11:39:20 +00:00
"""
2015-03-23 15:36:51 +00:00
verbose_name = _("Wordpress multisite")
2015-06-09 11:16:36 +00:00
model = 'saas.SaaS'
default_route_match = "saas.service == 'wordpress'"
2015-04-24 11:39:20 +00:00
doc_settings = (settings,
2015-09-29 12:35:22 +00:00
('SAAS_WORDPRESS_ADMIN_PASSWORD', 'SAAS_WORDPRESS_MAIN_URL')
2015-04-24 11:39:20 +00:00
)
2015-03-23 15:36:51 +00:00
def login(self, session):
2015-09-29 12:35:22 +00:00
main_url = self.get_main_url()
login_url = main_url + '/wp-login.php'
2015-03-23 15:36:51 +00:00
login_data = {
'log': 'admin',
2015-04-24 11:39:20 +00:00
'pwd': settings.SAAS_WORDPRESS_ADMIN_PASSWORD,
2015-03-23 15:36:51 +00:00
'redirect_to': '/wp-admin/'
}
response = session.post(login_url, data=login_data)
2015-09-29 12:35:22 +00:00
if response.url != main_url + '/wp-admin/':
2015-03-23 15:36:51 +00:00
raise IOError("Failure login to remote application")
2015-09-29 12:35:22 +00:00
def get_main_url(self):
main_url = settings.SAAS_WORDPRESS_MAIN_URL
return main_url.rstrip('/')
2015-03-23 15:36:51 +00:00
def validate_response(self, response):
if response.status_code != 200:
2015-04-20 14:23:10 +00:00
errors = re.findall(r'<body id="error-page">\n\t<p>(.*)</p></body>', response.content.decode('utf8'))
2015-03-23 15:36:51 +00:00
raise RuntimeError(errors[0] if errors else 'Unknown %i error' % response.status_code)
def get_id(self, session, saas):
2015-10-08 13:54:39 +00:00
blog_id = saas.data.get('blog_id')
2015-09-29 12:35:22 +00:00
search = self.get_main_url()
search += '/wp-admin/network/sites.php?s=%s&action=blogs' % saas.name
2015-03-23 15:36:51 +00:00
regex = re.compile(
'<a href="http://[\.\-\w]+/wp-admin/network/site-info\.php\?id=([0-9]+)"\s+'
'class="edit">%s</a>' % saas.name
2015-03-23 15:36:51 +00:00
)
2015-04-20 14:23:10 +00:00
content = session.get(search).content.decode('utf8')
2015-03-23 15:36:51 +00:00
# Get id
ids = regex.search(content)
2015-10-08 13:54:39 +00:00
if not ids and not blog_id:
raise RuntimeError("Blog '%s' not found" % saas.name)
2015-10-08 13:54:39 +00:00
if ids:
ids = ids.groups()
if len(ids) > 1 and not blog_id:
raise ValueError("Multiple matches")
2015-03-23 15:36:51 +00:00
# Get wpnonce
2015-10-08 13:54:39 +00:00
try:
wpnonce = re.search(r'<span class="delete">(.*)</span>', content).groups()[0]
except TypeError:
# No search results, try some luck
wpnonce = content
2015-03-23 15:36:51 +00:00
wpnonce = re.search(r'_wpnonce=([^"]*)"', wpnonce).groups()[0]
2015-10-08 13:54:39 +00:00
return blog_id or int(ids[0]), wpnonce
2015-03-23 15:36:51 +00:00
def create_blog(self, saas, server):
2015-10-08 13:54:39 +00:00
if saas.data.get('blog_id'):
return
2015-03-23 15:36:51 +00:00
session = requests.Session()
self.login(session)
# Check if blog already exists
try:
2015-10-08 13:54:39 +00:00
blog_id, wpnonce = self.get_id(session, saas)
2015-03-23 15:36:51 +00:00
except RuntimeError:
2015-09-29 12:35:22 +00:00
url = self.get_main_url()
2015-03-23 15:36:51 +00:00
url += '/wp-admin/network/site-new.php'
2015-04-20 14:23:10 +00:00
content = session.get(url).content.decode('utf8')
2015-03-23 15:36:51 +00:00
wpnonce = re.compile('name="_wpnonce_add-blog"\s+value="([^"]*)"')
wpnonce = wpnonce.search(content).groups()[0]
url += '?action=add-site'
data = {
'blog[domain]': saas.name,
'blog[title]': saas.name,
'blog[email]': saas.account.email,
2015-03-23 15:36:51 +00:00
'_wpnonce_add-blog': wpnonce,
}
# Validate response
response = session.post(url, data=data)
self.validate_response(response)
2015-10-08 13:54:39 +00:00
blog_id = re.compile(r'<link id="wp-admin-canonical" rel="canonical" href="http(?:[^ ]+)/wp-admin/network/site-new.php\?id=([0-9]+)" />')
content = response.content.decode('utf8')
blog_id = blog_id.search(content).groups()[0]
sys.stdout.write("Created blog ID: %s\n" % blog_id)
saas.data['blog_id'] = int(blog_id)
saas.save(update_fields=('data',))
else:
sys.stdout.write("Retrieved blog ID: %s\n" % blog_id)
saas.data['blog_id'] = int(blog_id)
saas.save(update_fields=('data',))
2015-03-23 15:36:51 +00:00
def delete_blog(self, saas, server):
2015-03-23 15:36:51 +00:00
session = requests.Session()
self.login(session)
try:
id, wpnonce = self.get_id(session, saas)
2015-03-23 15:36:51 +00:00
except RuntimeError:
pass
else:
2015-09-29 12:35:22 +00:00
delete = self.get_main_url()
2015-03-23 15:36:51 +00:00
delete += '/wp-admin/network/sites.php?action=confirm&action2=deleteblog'
delete += '&id=%d&_wpnonce=%s' % (id, wpnonce)
2015-04-20 14:23:10 +00:00
content = session.get(delete).content.decode('utf8')
2015-03-23 15:36:51 +00:00
wpnonce = re.compile('name="_wpnonce"\s+value="([^"]*)"')
wpnonce = wpnonce.search(content).groups()[0]
data = {
'action': 'deleteblog',
'id': id,
'_wpnonce': wpnonce,
'_wp_http_referer': '/wp-admin/network/sites.php',
}
2015-09-29 12:35:22 +00:00
delete = self.get_main_url()
2015-03-23 15:36:51 +00:00
delete += '/wp-admin/network/sites.php?action=deleteblog'
response = session.post(delete, data=data)
self.validate_response(response)
def save(self, saas):
self.append(self.create_blog, saas)
context = self.get_context(saas)
2015-10-08 13:54:39 +00:00
context['IDENT'] = "b.domain = '%(domain)s'" % context
if context['blog_id']:
context['IDENT'] = "b.blog_id = '%(blog_id)s'" % context
self.append(textwrap.dedent("""
# Update custom URL mapping
2015-10-08 13:54:39 +00:00
existing=( $(mysql -Nrs %(db_name)s --execute="
SELECT b.blog_id, b.domain, m.domain, b.path
FROM wp_domain_mapping AS m, wp_blogs AS b
2015-10-08 13:54:39 +00:00
WHERE m.blog_id = b.blog_id AND m.active AND %(IDENT)s;") )
2016-03-04 09:46:39 +00:00
if [[ ${existing[0]} != "" ]]; then
echo "Existing blog with ID ${existing[0]}"
2015-10-08 13:54:39 +00:00
# Clear custom domain
if [[ "%(custom_domain)s" == "" ]]; then
mysql %(db_name)s --execute="
2015-10-08 13:54:39 +00:00
DELETE FROM m
USING wp_domain_mapping AS m, wp_blogs AS b
WHERE m.blog_id = b.blog_id AND m.active AND %(IDENT)s;
UPDATE wp_blogs
SET path='/'
2015-10-29 18:19:00 +00:00
WHERE blog_id = ${existing[0]};"
elif [[ "${existing[2]}" != "%(custom_domain)s" || "${existing[3]}" != "%(custom_path)s" ]]; then
2015-10-08 13:54:39 +00:00
mysql %(db_name)s --execute="
UPDATE wp_domain_mapping as m, wp_blogs as b
2015-10-08 13:54:39 +00:00
SET m.domain = '%(custom_domain)s', b.path = '%(custom_path)s'
WHERE m.blog_id = b.blog_id AND m.active AND %(IDENT)s;"
fi
2015-10-08 13:54:39 +00:00
elif [[ "%(custom_domain)s" != "" ]]; then
2016-03-04 09:46:39 +00:00
echo "Non existing blog with custom domain %(domain)s"
2015-10-08 13:54:39 +00:00
blog=( $(mysql -Nrs %(db_name)s --execute="
2015-10-29 18:19:00 +00:00
SELECT blog_id, path
FROM wp_blogs
WHERE domain = '%(domain)s';") )
2016-03-04 09:46:39 +00:00
if [[ "${blog[0]}" != "" ]]; then
echo "Blog %(domain)s found, ID: ${blog[0]}"
mysql %(db_name)s --execute="
2016-03-04 09:46:39 +00:00
UPDATE wp_domain_mapping
SET active = 0
WHERE active AND blog_id = ${blog[0]};
INSERT INTO wp_domain_mapping
(blog_id, domain, active) VALUES (${blog[0]}, '%(custom_domain)s', 1);"
if [[ "${blog[1]}" != "%(custom_path)s" ]]; then
mysql %(db_name)s --execute="
UPDATE wp_blogs
SET path = '%(custom_path)s'
WHERE blog_id = ${blog[0]};"
fi
else
echo "Blog %(domain)s not found"
fi
fi""") % context
)
2015-03-23 15:36:51 +00:00
def delete(self, saas):
self.append(self.delete_blog, saas)
def get_context(self, saas):
domain = saas.get_site_domain()
context = {
'db_name': settings.SAAS_WORDPRESS_DB_NAME,
'domain': domain,
2015-10-08 13:54:39 +00:00
'custom_domain': '',
'custom_path': '/',
'blog_id': saas.data.get('blog_id', ''),
}
if saas.custom_url:
custom_url = urlparse(saas.custom_url)
context.update({
'custom_domain': custom_url.netloc,
'custom_path': custom_url.path,
})
return context
2016-03-04 09:46:39 +00:00
class WordpressMuTraffic(ApacheTrafficByHost):
__doc__ = ApacheTrafficByHost.__doc__
verbose_name = _("Wordpress MU Traffic")
default_route_match = "saas.service == 'wordpress'"
doc_settings = (settings,
('SAAS_TRAFFIC_IGNORE_HOSTS', 'SAAS_WORDPRESS_LOG_PATH')
)
log_path = settings.SAAS_WORDPRESS_LOG_PATH