diff options
author | David Negreira <david.negreira@canonical.com> | 2020-02-13 00:35:18 +0100 |
---|---|---|
committer | Bryan Quigley <bryan.quigley@canonical.com> | 2020-02-12 22:23:52 -0800 |
commit | b3d6b053ba65dcff29c3db9e2f7c061af0ba33fb (patch) | |
tree | a5a320abdfc3bc374c1eda5495f0d3db368856cc | |
parent | 3657bcbbc41be60c9f12c8391057b72ae053bd95 (diff) | |
download | sos-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.py | 131 |
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 : |