← Back to team overview

wordpress-charmers team mailing list archive

[Merge] ~mthaddon/charm-k8s-wordpress/+git/charm-k8s-wordpress:admin-password-action into charm-k8s-wordpress:master

 

Tom Haddon has proposed merging ~mthaddon/charm-k8s-wordpress/+git/charm-k8s-wordpress:admin-password-action into charm-k8s-wordpress:master.

Commit message:
Add an action to retrieve initial password

Requested reviews:
  Wordpress Charmers (wordpress-charmers)
Related bugs:
  Bug #1907063 in charm-k8s-wordpress: "Add a juju action to retrieve admin password"
  https://bugs.launchpad.net/charm-k8s-wordpress/+bug/1907063

For more details, see:
https://code.launchpad.net/~mthaddon/charm-k8s-wordpress/+git/charm-k8s-wordpress/+merge/395982

Add an action to retrieve initial password
-- 
Your team Wordpress Charmers is requested to review the proposed merge of ~mthaddon/charm-k8s-wordpress/+git/charm-k8s-wordpress:admin-password-action into charm-k8s-wordpress:master.
diff --git a/README.md b/README.md
index 886c92a..bd66985 100644
--- a/README.md
+++ b/README.md
@@ -73,9 +73,9 @@ and perform the initial setup for you. Look for this line in the output of
 This is due to [issue #166](https://github.com/canonical/operator/issues/166) and will be fixed once Juju supports a Kubernetes
 pod ready hook.
 
-To retrieve the random admin password, run the following (until [LP#1907063](https://bugs.launchpad.net/charm-k8s-wordpress/+bug/1907063) is addressed):
+To retrieve the auto-generated admin password, run the following:
 
-    microk8s.kubectl exec -ti -n wordpress wordpress-operator-0 -- cat /root/initial.passwd
+    juju run-action --wait wordpress/0 get-initial-password
 
 You should now be able to browse to https://myblog.example.com/wp-admin.
 
diff --git a/actions.yaml b/actions.yaml
new file mode 100644
index 0000000..796aa4e
--- /dev/null
+++ b/actions.yaml
@@ -0,0 +1,2 @@
+get-initial-password:
+  description: Retrieve the auto-generated initial password.
diff --git a/src/charm.py b/src/charm.py
index edade47..ec309da 100755
--- a/src/charm.py
+++ b/src/charm.py
@@ -115,8 +115,11 @@ class WordpressCharm(CharmBase):
         self.framework.observe(self.on.update_status, self.on_config_changed)
         self.framework.observe(self.on.wordpress_initialise, self.on_wordpress_initialise)
 
+        # Actions.
+        self.framework.observe(self.on.get_initial_password_action, self._on_get_initial_password_action)
+
         self.state.set_default(
-            initialised=False, valid=False,
+            initialised=False, initial_password=None, valid=False,
         )
 
         self.wordpress = Wordpress(self.model.config)
@@ -146,7 +149,8 @@ class WordpressCharm(CharmBase):
             msg = "Wordpress needs configuration"
             logger.info(msg)
             self.model.unit.status = MaintenanceStatus(msg)
-            installed = self.wordpress.first_install(self.get_service_ip())
+            admin_password = password_generator()
+            installed = self.wordpress.first_install(self.get_service_ip(), admin_password)
             if not installed:
                 msg = "Failed to configure wordpress"
                 logger.info(msg)
@@ -154,6 +158,7 @@ class WordpressCharm(CharmBase):
                 return
 
             self.state.initialised = True
+            self.state.initial_password = admin_password
             logger.info("Wordpress configured and initialised")
             self.model.unit.status = ActiveStatus()
 
@@ -287,6 +292,13 @@ class WordpressCharm(CharmBase):
             return self.wordpress.is_vhost_ready(service_ip)
         return False
 
+    def _on_get_initial_password_action(self, event):
+        """Handle the get-initial-password action."""
+        if self.state.initial_password:
+            event.set_results({"initial_password": self.state.initial_password})
+        else:
+            event.fail("Initial password has not been set yet.")
+
 
 if __name__ == "__main__":
     main(WordpressCharm)
diff --git a/src/wordpress.py b/src/wordpress.py
index a3f586e..9ac5336 100644
--- a/src/wordpress.py
+++ b/src/wordpress.py
@@ -44,15 +44,10 @@ class Wordpress:
     def __init__(self, model_config):
         self.model_config = model_config
 
-    def _write_initial_password(self, password, filepath):
-        with open(filepath, "w") as f:
-            f.write(password)
-
-    def first_install(self, service_ip):
+    def first_install(self, service_ip, admin_password):
         """Perform initial configuration of wordpress if needed."""
         config = self.model_config
         logger.info("Starting wordpress initial configuration")
-        admin_password = password_generator()
         payload = {
             "admin_password": admin_password,
             "blog_public": "checked",
@@ -61,12 +56,6 @@ class Wordpress:
         payload.update(safe_load(config["initial_settings"]))
         payload["admin_password2"] = payload["admin_password"]
 
-        # Ideally we would store this in state however juju run-action does not
-        # currently support being run inside the operator pod which means the
-        # StorageState will be split between workload and operator.
-        # https://bugs.launchpad.net/juju/+bug/1870487
-        self._write_initial_password(payload["admin_password"], "/root/initial.passwd")
-
         if not payload["blog_public"]:
             payload["blog_public"] = "unchecked"
         required_config = set(("user_name", "admin_email"))
diff --git a/tests/unit/test_charm.py b/tests/unit/test_charm.py
index 1840a4c..4820aa2 100644
--- a/tests/unit/test_charm.py
+++ b/tests/unit/test_charm.py
@@ -4,6 +4,8 @@ import copy
 import mock
 import unittest
 
+from unittest.mock import Mock
+
 from charm import WordpressCharm, create_wordpress_secrets, gather_wordpress_secrets
 from wordpress import WORDPRESS_SECRETS
 from ops import testing
@@ -124,3 +126,14 @@ class TestWordpressCharm(unittest.TestCase):
             }
         }
         self.assertEqual(self.harness.charm.make_pod_resources(), expected)
+
+    def test_on_get_initial_password_action(self):
+        action_event = Mock()
+        # First test with no initial password set.
+        self.assertEqual(self.harness.charm.state.initial_password, None)
+        self.harness.charm._on_get_initial_password_action(action_event)
+        self.assertEqual(action_event.fail.call_args, mock.call("Initial password has not been set yet."))
+        # Now test with initial password set.
+        self.harness.charm.state.initial_password = "passwd"
+        self.harness.charm._on_get_initial_password_action(action_event)
+        self.assertEqual(action_event.set_results.call_args, mock.call({"initial_password": "passwd"}))
diff --git a/tests/unit/test_wordpress.py b/tests/unit/test_wordpress.py
index f204cac..92712e7 100644
--- a/tests/unit/test_wordpress.py
+++ b/tests/unit/test_wordpress.py
@@ -94,13 +94,10 @@ class WordpressTest(unittest.TestCase):
     def test__init__(self):
         self.assertEqual(self.test_wordpress.model_config, self.test_model_config)
 
-    @mock.patch("wordpress.password_generator", side_effect=dummy_password_generator)
-    def test_first_install(self, password_generator_func):
+    def test_first_install(self):
         mocked_call_wordpress = mock.MagicMock(name="call_wordpress", return_value=True)
-        mocked__write_initial_password = mock.MagicMock(name="_write_initial_password", return_value=None)
         mocked_wordpress_configured = mock.MagicMock(name="wordpress_configured", return_value=True)
         self.test_wordpress.call_wordpress = mocked_call_wordpress
-        self.test_wordpress._write_initial_password = mocked__write_initial_password
         self.test_wordpress.wordpress_configured = mocked_wordpress_configured
 
         test_payload = {
@@ -112,10 +109,7 @@ class WordpressTest(unittest.TestCase):
             'admin_email': 'root@xxxxxxxxxxxxxxxxxxx',
             'weblog_title': 'Test Blog',
         }
-        self.test_wordpress.first_install(self.test_service_ip)
-
-        # Test that we wrote initial admin credentials inside the operator pod.
-        self.test_wordpress._write_initial_password.assert_called_with(TEST_GENERATED_PASSWORD, "/root/initial.passwd")
+        self.test_wordpress.first_install(self.test_service_ip, TEST_GENERATED_PASSWORD)
 
         # Test that we POST'd our initial configuration options to the wordpress API.
         self.test_wordpress.call_wordpress.assert_called_with(
@@ -128,7 +122,7 @@ class WordpressTest(unittest.TestCase):
         self.test_wordpress.model_config["initial_settings"] = (
             "user_name: admin\n" "weblog_title: Test Blog\n" "blog_public: False"
         )
-        self.test_wordpress.first_install(self.test_service_ip)
+        self.test_wordpress.first_install(self.test_service_ip, TEST_GENERATED_PASSWORD)
         self.test_wordpress.call_wordpress.assert_not_called()
 
     def test_wordpress_configured(self):

Follow ups