aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Negreira <david.negreira@canonical.com>2020-02-13 00:35:18 +0100
committerBryan Quigley <bryan.quigley@canonical.com>2020-02-12 22:23:52 -0800
commitb3d6b053ba65dcff29c3db9e2f7c061af0ba33fb (patch)
treea5a320abdfc3bc374c1eda5495f0d3db368856cc
parent3657bcbbc41be60c9f12c8391057b72ae053bd95 (diff)
downloadsos-b3d6b053ba65dcff29c3db9e2f7c061af0ba33fb.tar.gz
[Juju] Juju Plugin Refactoring
Since the current plugin is having issues when we run sosreport on a juju controller we have decided to refactor it and make it simpler. We had some discussions following three separate PRs: https://github.com/sosreport/sos/pull/1670 https://github.com/sosreport/sos/pull/1671 https://github.com/sosreport/sos/pull/1672 We decided not to gather mongodb dumps as it will leak the password from mongodb when running `ps`. We decided to drop the output from juju commands as this requires the command to be run as the user that holds the juju credentials. This plugin will gather logs from `/var/log/juju/*.log` and agent configuration files from `/var/lib/juju/agents/*/agent.conf`, as well as systemd logs related to the agents. If sosreport is run with `--all-logs` it will gather all of the above as well as all the files from `/var/lib/juju/` and `/var/log/juju`. Closes: #1653 Resolves: #1935 Co-authored-by: David Negreira david.negreira@canonical.com Co-authored-by: Nick Niehoff nick.niehoff@canonical.com Signed-off-by: David Negreira david.negreira@canonical.com Signed-off-by: Bryan Quigley <bryan.quigley@canonical.com>
-rw-r--r--sos/plugins/juju.py131
1 files changed, 40 insertions, 91 deletions
diff --git a/sos/plugins/juju.py b/sos/plugins/juju.py
index 4574bc66..65f19474 100644
--- a/sos/plugins/juju.py
+++ b/sos/plugins/juju.py
@@ -8,27 +8,7 @@
#
# See the LICENSE file in the source distribution for further information.
-import os
from sos.plugins import Plugin, UbuntuPlugin
-from json import loads as json_loads
-
-
-def ensure_service_is_running(service):
- def wrapper(callback):
- def wrapped_f(self, *args, **kwargs):
- try:
- result = self.call_ext_prog("service {0} stop".format(service))
- if result["status"] != 0:
- raise Exception("Cannot stop {0} service".format(service))
- callback(self, *args, **kwargs)
- except Exception as ex:
- self._log_error("Cannot stop {0}, exception: {1}".format(
- service,
- ex.message))
- finally:
- self.call_ext_prog("service {0} start".format(service))
- return wrapped_f
- return wrapper
class Juju(Plugin, UbuntuPlugin):
@@ -37,85 +17,54 @@ class Juju(Plugin, UbuntuPlugin):
plugin_name = 'juju'
profiles = ('virt', 'sysmgmt')
- files = ('/usr/bin/juju', '/usr/bin/juju-run', '/snap/bin/juju')
-
- option_list = [
- ('export-mongodb',
- 'Export mongodb collections as json files', '', False),
- ('generate-bundle',
- """Generate a YAML bundle of the current environment
- (requires juju-deployerizer)""", '', False),
- ]
- def get_deployed_services(self):
- cmd = "juju status --format json"
- status_json = self.call_ext_prog(cmd)['output']
- self.add_string_as_file(status_json, "juju_status_json")
- # if status_json isn't in JSON format (i.e. 'juju' command not found),
- # or if it does not contain 'services' key, return empty list
- try:
- return json_loads(status_json)['services'].keys()
- except ValueError:
- return []
+ # Using files instead of packages here because there is no identifying
+ # package on a juju machine.
+ files = ('/var/log/juju')
- @ensure_service_is_running("juju-db")
- def export_mongodb(self):
- collections = (
- "relations",
- "environments",
- "linkednetworks",
- "system",
- "settings",
- )
+ def setup(self):
+ # Juju service names are not consistent through deployments,
+ # so we need to use a wildcard to get the correct service names.
+ for service in self.get_service_names("juju*"):
+ self.add_journal(service)
+ self.add_service_status(service)
- for collection in collections:
- self.add_cmd_output(
- "/usr/lib/juju/bin/mongoexport --ssl \
- --dbpath=/var/lib/juju/db --db juju --collection {0} \
- --jsonArray".format(collection),
- suggest_filename="{}.json".format(collection))
+ # Get agent configs for each agent.
+ self.add_copy_spec("/var/lib/juju/agents/*/agent.conf")
- def setup(self):
- self.add_copy_spec("/var/log/upstart/juju-db.log")
- self.add_copy_spec("/var/log/upstart/juju-db.log.1")
- if not self.get_option("all_logs"):
- # We need this because we want to collect to the limit of all
- # *.logs in the directory.
- if(os.path.isdir("/var/log/juju/")):
- for filename in os.listdir("/var/log/juju/"):
- if filename.endswith(".log"):
- fullname = os.path.join("/var/log/juju/" + filename)
- self.add_copy_spec(fullname)
- self.add_cmd_output('ls -alRh /var/log/juju*')
- self.add_cmd_output('ls -alRh /var/lib/juju/*')
+ # Get a directory listing of /var/log/juju and /var/lib/juju
+ self.add_cmd_output([
+ "ls -alRh /var/log/juju*",
+ "ls -alRh /var/lib/juju*"
+ ])
- else:
+ if self.get_option("all_logs"):
+ # /var/lib/juju used to be in the default capture moving here
+ # because it usually was way to big. However, in most cases you
+ # want all logs you want this too.
self.add_copy_spec([
"/var/log/juju",
- "/var/log/juju-*",
"/var/lib/juju"
- # /var/lib/juju used to be in the default capture moving here
- # because it usually was way to big. However, in most cases
- # you want all logs you want this too.
])
-
- self.add_cmd_output([
- "juju --version",
- "juju -v status --format=tabular",
- ])
- for service in self.get_deployed_services():
- self.add_cmd_output([
- "juju get {}".format(service),
- "juju get-config {}".format(service),
- "juju get-constraints {}".format(service)
- ])
-
- if self.get_option("export-mongodb"):
- self.export_mongodb()
-
- if self.get_option("generate-bundle"):
- self.add_cmd_output("juju deployerizer --include-charm-versions",
- suggest_filename="juju-env-bundle.yaml")
-
+ else:
+ # We need this because we want to collect to the limit of all
+ # logs in the directory.
+ self.add_copy_spec("/var/log/juju/*.log")
+
+ def postproc(self):
+ agents_path = "/var/lib/juju/agents/*"
+ protect_keys = [
+ "sharedsecret",
+ "apipassword",
+ "oldpassword",
+ "statepassword",
+ ]
+
+ # Redact simple yaml style "key: value".
+ keys_regex = r"((?m)^\s*(%s)\s*:\s*)(.*)" % "|".join(protect_keys)
+ sub_regex = r"\1*********"
+ self.do_path_regex_sub(agents_path, keys_regex, sub_regex)
+ # Redact certificates
+ self.do_file_private_sub(agents_path)
# vim: set et ts=4 sw=4 :