Merge ~barryprice/charm-k8s-wordpress/+git/charm-k8s-wordpress:master into charm-k8s-wordpress:master

Proposed by Barry Price
Status: Merged
Approved by: Barry Price
Approved revision: caada5147f1111a14afe20792c50617b2fdf9e07
Merged at revision: 972e302aea795b274e3846923a7049081e7d9472
Proposed branch: ~barryprice/charm-k8s-wordpress/+git/charm-k8s-wordpress:master
Merge into: charm-k8s-wordpress:master
Diff against target: 166 lines (+70/-14)
2 files modified
config.yaml (+8/-0)
reactive/wordpress.py (+62/-14)
Reviewer Review Type Date Requested Status
Stuart Bishop (community) Approve
Canonical IS Reviewers Pending
Review via email: mp+377904@code.launchpad.net

Commit message

Handle redirects better, detect and warn about missing DB config, add registry authentication support, fix status.maintenance() syntax error

To post a comment you must log in.
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

This merge proposal is being monitored by mergebot. Change the status to Approved to merge.

Revision history for this message
Stuart Bishop (stub) wrote :

This looks good. One comment inline for some minor code shuffling. Try not to include black code reformats together with other reviews.

review: Approve
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

Change successfully merged at revision 972e302aea795b274e3846923a7049081e7d9472

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/config.yaml b/config.yaml
index 842b2e2..a622726 100644
--- a/config.yaml
+++ b/config.yaml
@@ -3,6 +3,14 @@ options:
3 type: string3 type: string
4 description: "The docker image to install. Required. Defaults to Dockerhub wordpress:php7.3"4 description: "The docker image to install. Required. Defaults to Dockerhub wordpress:php7.3"
5 default: "wordpress:php7.3"5 default: "wordpress:php7.3"
6 image_user:
7 type: string
8 description: "Username to use for the configured image registry, if required"
9 default: ""
10 image_pass:
11 type: string
12 description: "Password to use for the configured image registry, if required"
13 default: ""
6 ports:14 ports:
7 type: string15 type: string
8 description: >16 description: >
diff --git a/reactive/wordpress.py b/reactive/wordpress.py
index 39ea6dc..d54ac58 100644
--- a/reactive/wordpress.py
+++ b/reactive/wordpress.py
@@ -3,7 +3,7 @@ import os
3import re3import re
4import requests4import requests
5from pprint import pprint5from pprint import pprint
6from urllib.parse import urlunparse6from urllib.parse import urlparse, urlunparse
7from yaml import safe_load7from yaml import safe_load
88
9from charmhelpers.core import host, hookenv9from charmhelpers.core import host, hookenv
@@ -14,7 +14,7 @@ from charms.reactive import hook, when, when_not
1414
15@hook("upgrade-charm")15@hook("upgrade-charm")
16def upgrade_charm():16def upgrade_charm():
17 status.maintenance("maintenance", "Upgrading charm")17 status.maintenance("Upgrading charm")
18 reactive.clear_flag("wordpress.configured")18 reactive.clear_flag("wordpress.configured")
1919
2020
@@ -108,14 +108,27 @@ def make_pod_spec():
108 # PodSpec v1? https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.13/#podspec-v1-core108 # PodSpec v1? https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.13/#podspec-v1-core
109 spec = {109 spec = {
110 "containers": [110 "containers": [
111 {"name": hookenv.charm_name(), "image": config["image"], "ports": ports, "config": container_config}111 {
112 "name": hookenv.charm_name(),
113 "imageDetails": {"imagePath": config["image"]},
114 "ports": ports,
115 "config": container_config,
116 }
112 ]117 ]
113 }118 }
114 out = io.StringIO()119 out = io.StringIO()
115 pprint(spec, out)120 pprint(spec, out)
116 hookenv.log("Container spec (sans secrets) <<EOM\n{}\nEOM".format(out.getvalue()))121 hookenv.log(
122 "Container environment config (sans secrets) <<EOM\n{}\nEOM".format(
123 out.getvalue()
124 )
125 )
126
127 # if we need credentials (secrets) for our image, add them to the spec after logging
128 if config.get("image_user") and config.get("image_pass"):
129 spec.get("containers")[0].get("imageDetails")["username"] = config["image_user"]
130 spec.get("containers")[0].get("imageDetails")["password"] = config["image_pass"]
117131
118 # Add the secrets after logging
119 config_with_secrets = full_container_config()132 config_with_secrets = full_container_config()
120 if config_with_secrets is None:133 if config_with_secrets is None:
121 return None # status already set134 return None # status already set
@@ -134,10 +147,16 @@ def first_install():
134 hookenv.log("Wordpress vhost is not yet listening - retrying")147 hookenv.log("Wordpress vhost is not yet listening - retrying")
135 return False148 return False
136 elif wordpress_configured() or not config["initial_settings"]:149 elif wordpress_configured() or not config["initial_settings"]:
137 hookenv.log("No initial_setting provided or wordpress already configured. Skipping first install.")150 hookenv.log(
151 "No initial_setting provided or wordpress already configured. Skipping first install."
152 )
138 return True153 return True
139 hookenv.log("Starting wordpress initial configuration")154 hookenv.log("Starting wordpress initial configuration")
140 payload = {"admin_password": host.pwgen(24), "blog_public": "checked", "Submit": "submit"}155 payload = {
156 "admin_password": host.pwgen(24),
157 "blog_public": "checked",
158 "Submit": "submit",
159 }
141 payload.update(safe_load(config["initial_settings"]))160 payload.update(safe_load(config["initial_settings"]))
142 payload["admin_password2"] = payload["admin_password"]161 payload["admin_password2"] = payload["admin_password"]
143 if not payload["blog_public"]:162 if not payload["blog_public"]:
@@ -147,21 +166,37 @@ def first_install():
147 if missing:166 if missing:
148 hookenv.log("Error: missing wordpress settings: {}".format(missing))167 hookenv.log("Error: missing wordpress settings: {}".format(missing))
149 return False168 return False
150 call_wordpress("/wp-admin/install.php?step=2", payload=payload)169 call_wordpress("/wp-admin/install.php?step=2", redirects=True, payload=payload)
151 host.write_file(os.path.join("/root/", "initial.passwd"), payload["admin_password"], perms=0o400)170 host.write_file(
171 os.path.join("/root/", "initial.passwd"), payload["admin_password"], perms=0o400
172 )
152 return True173 return True
153174
154175
155def call_wordpress(uri, redirects=True, payload={}):176def call_wordpress(uri, redirects=True, payload={}, _depth=1):
177 max_depth = 10
178 if _depth > max_depth:
179 hookenv.log("Redirect loop detected in call_worpress()")
180 raise RuntimeError("Redirect loop detected in call_worpress()")
156 config = hookenv.config()181 config = hookenv.config()
157 service_ip = get_service_ip("website")182 service_ip = get_service_ip("website")
158 if service_ip:183 if service_ip:
159 headers = {"Host": config["blog_hostname"]}184 headers = {"Host": config["blog_hostname"]}
160 url = urlunparse(("http", service_ip, uri, "", "", ""))185 url = urlunparse(("http", service_ip, uri, "", "", ""))
161 if payload:186 if payload:
162 return requests.post(url, allow_redirects=redirects, headers=headers, data=payload)187 r = requests.post(
188 url, allow_redirects=False, headers=headers, data=payload, timeout=30
189 )
190 else:
191 r = requests.get(url, allow_redirects=False, headers=headers, timeout=30)
192 if redirects and r.is_redirect:
193 # recurse, but strip the scheme and host first, we need to connect over HTTP by bare IP
194 o = urlparse(r.headers.get("Location"))
195 return call_wordpress(
196 o.path, redirects=redirects, payload=payload, _depth=_depth + 1
197 )
163 else:198 else:
164 return requests.get(url, allow_redirects=redirects, headers=headers)199 return r
165 else:200 else:
166 hookenv.log("Error getting service IP")201 hookenv.log("Error getting service IP")
167 return False202 return False
@@ -180,7 +215,15 @@ def wordpress_configured():
180 r = call_wordpress("/", redirects=False)215 r = call_wordpress("/", redirects=False)
181 except requests.exceptions.ConnectionError:216 except requests.exceptions.ConnectionError:
182 return False217 return False
183 if r.status_code == 302 and re.match("^.*/wp-admin/install.php", r.headers.get("location", "")):218 if r.status_code == 302 and re.match(
219 "^.*/wp-admin/install.php", r.headers.get("location", "")
220 ):
221 return False
222 elif r.status_code == 302 and re.match(
223 "^.*/wp-admin/setup-config.php", r.headers.get("location", "")
224 ):
225 hookenv.log("MySQL database setup failed, we likely have no wp-config.php")
226 status.blocked("MySQL database setup failed, we likely have no wp-config.php")
184 return False227 return False
185 else:228 else:
186 return True229 return True
@@ -192,8 +235,13 @@ def is_vhost_ready():
192 try:235 try:
193 r = call_wordpress("/wp-login.php", redirects=False)236 r = call_wordpress("/wp-login.php", redirects=False)
194 except requests.exceptions.ConnectionError:237 except requests.exceptions.ConnectionError:
238 hookenv.log("call_wordpress() returned requests.exceptions.ConnectionError")
239 return False
240 if r is None:
241 hookenv.log("call_wordpress() returned None")
195 return False242 return False
196 if r.status_code in (403, 404):243 if hasattr(r, "status_code") and r.status_code in (403, 404):
244 hookenv.log("call_wordpress() returned status {}".format(r.status_code))
197 return False245 return False
198 else:246 else:
199 return True247 return True

Subscribers

People subscribed via source and target branches