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
1diff --git a/config.yaml b/config.yaml
2index 842b2e2..a622726 100644
3--- a/config.yaml
4+++ b/config.yaml
5@@ -3,6 +3,14 @@ options:
6 type: string
7 description: "The docker image to install. Required. Defaults to Dockerhub wordpress:php7.3"
8 default: "wordpress:php7.3"
9+ image_user:
10+ type: string
11+ description: "Username to use for the configured image registry, if required"
12+ default: ""
13+ image_pass:
14+ type: string
15+ description: "Password to use for the configured image registry, if required"
16+ default: ""
17 ports:
18 type: string
19 description: >
20diff --git a/reactive/wordpress.py b/reactive/wordpress.py
21index 39ea6dc..d54ac58 100644
22--- a/reactive/wordpress.py
23+++ b/reactive/wordpress.py
24@@ -3,7 +3,7 @@ import os
25 import re
26 import requests
27 from pprint import pprint
28-from urllib.parse import urlunparse
29+from urllib.parse import urlparse, urlunparse
30 from yaml import safe_load
31
32 from charmhelpers.core import host, hookenv
33@@ -14,7 +14,7 @@ from charms.reactive import hook, when, when_not
34
35 @hook("upgrade-charm")
36 def upgrade_charm():
37- status.maintenance("maintenance", "Upgrading charm")
38+ status.maintenance("Upgrading charm")
39 reactive.clear_flag("wordpress.configured")
40
41
42@@ -108,14 +108,27 @@ def make_pod_spec():
43 # PodSpec v1? https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.13/#podspec-v1-core
44 spec = {
45 "containers": [
46- {"name": hookenv.charm_name(), "image": config["image"], "ports": ports, "config": container_config}
47+ {
48+ "name": hookenv.charm_name(),
49+ "imageDetails": {"imagePath": config["image"]},
50+ "ports": ports,
51+ "config": container_config,
52+ }
53 ]
54 }
55 out = io.StringIO()
56 pprint(spec, out)
57- hookenv.log("Container spec (sans secrets) <<EOM\n{}\nEOM".format(out.getvalue()))
58+ hookenv.log(
59+ "Container environment config (sans secrets) <<EOM\n{}\nEOM".format(
60+ out.getvalue()
61+ )
62+ )
63+
64+ # if we need credentials (secrets) for our image, add them to the spec after logging
65+ if config.get("image_user") and config.get("image_pass"):
66+ spec.get("containers")[0].get("imageDetails")["username"] = config["image_user"]
67+ spec.get("containers")[0].get("imageDetails")["password"] = config["image_pass"]
68
69- # Add the secrets after logging
70 config_with_secrets = full_container_config()
71 if config_with_secrets is None:
72 return None # status already set
73@@ -134,10 +147,16 @@ def first_install():
74 hookenv.log("Wordpress vhost is not yet listening - retrying")
75 return False
76 elif wordpress_configured() or not config["initial_settings"]:
77- hookenv.log("No initial_setting provided or wordpress already configured. Skipping first install.")
78+ hookenv.log(
79+ "No initial_setting provided or wordpress already configured. Skipping first install."
80+ )
81 return True
82 hookenv.log("Starting wordpress initial configuration")
83- payload = {"admin_password": host.pwgen(24), "blog_public": "checked", "Submit": "submit"}
84+ payload = {
85+ "admin_password": host.pwgen(24),
86+ "blog_public": "checked",
87+ "Submit": "submit",
88+ }
89 payload.update(safe_load(config["initial_settings"]))
90 payload["admin_password2"] = payload["admin_password"]
91 if not payload["blog_public"]:
92@@ -147,21 +166,37 @@ def first_install():
93 if missing:
94 hookenv.log("Error: missing wordpress settings: {}".format(missing))
95 return False
96- call_wordpress("/wp-admin/install.php?step=2", payload=payload)
97- host.write_file(os.path.join("/root/", "initial.passwd"), payload["admin_password"], perms=0o400)
98+ call_wordpress("/wp-admin/install.php?step=2", redirects=True, payload=payload)
99+ host.write_file(
100+ os.path.join("/root/", "initial.passwd"), payload["admin_password"], perms=0o400
101+ )
102 return True
103
104
105-def call_wordpress(uri, redirects=True, payload={}):
106+def call_wordpress(uri, redirects=True, payload={}, _depth=1):
107+ max_depth = 10
108+ if _depth > max_depth:
109+ hookenv.log("Redirect loop detected in call_worpress()")
110+ raise RuntimeError("Redirect loop detected in call_worpress()")
111 config = hookenv.config()
112 service_ip = get_service_ip("website")
113 if service_ip:
114 headers = {"Host": config["blog_hostname"]}
115 url = urlunparse(("http", service_ip, uri, "", "", ""))
116 if payload:
117- return requests.post(url, allow_redirects=redirects, headers=headers, data=payload)
118+ r = requests.post(
119+ url, allow_redirects=False, headers=headers, data=payload, timeout=30
120+ )
121+ else:
122+ r = requests.get(url, allow_redirects=False, headers=headers, timeout=30)
123+ if redirects and r.is_redirect:
124+ # recurse, but strip the scheme and host first, we need to connect over HTTP by bare IP
125+ o = urlparse(r.headers.get("Location"))
126+ return call_wordpress(
127+ o.path, redirects=redirects, payload=payload, _depth=_depth + 1
128+ )
129 else:
130- return requests.get(url, allow_redirects=redirects, headers=headers)
131+ return r
132 else:
133 hookenv.log("Error getting service IP")
134 return False
135@@ -180,7 +215,15 @@ def wordpress_configured():
136 r = call_wordpress("/", redirects=False)
137 except requests.exceptions.ConnectionError:
138 return False
139- if r.status_code == 302 and re.match("^.*/wp-admin/install.php", r.headers.get("location", "")):
140+ if r.status_code == 302 and re.match(
141+ "^.*/wp-admin/install.php", r.headers.get("location", "")
142+ ):
143+ return False
144+ elif r.status_code == 302 and re.match(
145+ "^.*/wp-admin/setup-config.php", r.headers.get("location", "")
146+ ):
147+ hookenv.log("MySQL database setup failed, we likely have no wp-config.php")
148+ status.blocked("MySQL database setup failed, we likely have no wp-config.php")
149 return False
150 else:
151 return True
152@@ -192,8 +235,13 @@ def is_vhost_ready():
153 try:
154 r = call_wordpress("/wp-login.php", redirects=False)
155 except requests.exceptions.ConnectionError:
156+ hookenv.log("call_wordpress() returned requests.exceptions.ConnectionError")
157+ return False
158+ if r is None:
159+ hookenv.log("call_wordpress() returned None")
160 return False
161- if r.status_code in (403, 404):
162+ if hasattr(r, "status_code") and r.status_code in (403, 404):
163+ hookenv.log("call_wordpress() returned status {}".format(r.status_code))
164 return False
165 else:
166 return True

Subscribers

People subscribed via source and target branches