diff options
author | Pep Turró Mauri <pep@redhat.com> | 2016-06-28 23:12:45 +0200 |
---|---|---|
committer | Bryn M. Reeves <bmr@redhat.com> | 2016-06-29 19:24:47 +0100 |
commit | dc37f9f720863cc981447e491fb470260e6636e0 (patch) | |
tree | 37d740a2e55d69ca13c3427d1896394e0393c5fa | |
parent | c72f2e1f3a13713a9902a8ee42857d124ff72933 (diff) | |
download | sos-dc37f9f720863cc981447e491fb470260e6636e0.tar.gz |
[origin] New plugin for OpenShift Origin / OSE 3.x
Add a new plugin to collect information about OpenShift Origin:
https://github.com/openshift/origin
https://www.openshift.org
and related products like Atomic Platform / OpenShift Enterprise 3+.
Fixes: #612
Fixes: RHBZ 1246423
Signed-off-by: Pep Turró Mauri <pep@redhat.com>
-rw-r--r-- | sos/plugins/openshift.py | 8 | ||||
-rw-r--r-- | sos/plugins/origin.py | 196 |
2 files changed, 203 insertions, 1 deletions
diff --git a/sos/plugins/openshift.py b/sos/plugins/openshift.py index b424eb91..67cd253d 100644 --- a/sos/plugins/openshift.py +++ b/sos/plugins/openshift.py @@ -16,8 +16,14 @@ from sos.plugins import Plugin, RedHatPlugin import os.path +# This plugin handles OpenShift Enterprise versions up to 2.x +# which are based in the upstream code of OpenShift Origin M4 +# located here: https://github.com/openshift/origin-server +# +# For later of OpenShift Origin based on: https://github.com/openshift/origin +# like OpenShift Enterprise 3.x see the origin.py plugin class Openshift(Plugin, RedHatPlugin): - '''Openshift node and broker''' + '''Openshift 2.x node and broker''' plugin_name = "openshift" profiles = ('virt', 'openshift') diff --git a/sos/plugins/origin.py b/sos/plugins/origin.py new file mode 100644 index 00000000..0f5482b7 --- /dev/null +++ b/sos/plugins/origin.py @@ -0,0 +1,196 @@ +# Copyright (C) 2016 Red Hat, Inc., Pep Turro Mauri <pep@redhat.com> + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +from sos.plugins import Plugin, RedHatPlugin +import os.path + +# This plugin collects static configuration and runtime information +# about OpenShift Origin based environments, like OpenShift Enterprise 3 + +# Some clarification on naming: +# OpenShift Origin is the upstream project for OpenShift Enterprise, +# OpenShift Container Platflorm, and Atomic Platform. +# +# However, the name "OpenShift Origin" refers to two different code bases: +# * Origin M5 and later (https://github.com/openshift/origin) +# which is upstream for OpenShift 3.x and later. +# This is what this plugin handles +# * Origin M4 and earlier (https://github.com/openshift/origin-server) +# which is upstream for OpenShift 1.x and 2.x. +# This is handled by the plugin in openshift.py + +# Note that this plugin should be used in conjunction with other plugins +# in order to capture relevant data: the Kubernetes plugin for the +# masters, the Docker plugin for the nodes, and also generic +# plugins (e.g. for /etc/sysconfig entries, network setup etc) + + +class OpenShiftOrigin(Plugin): + ''' OpenShift Origin ''' + + plugin_name = "origin" + files = None # file lists assigned after path setup below + profiles = ('openshift',) + + master_base_dir = "/etc/origin/master" + node_base_dir = "/etc/origin/node" + master_cfg = os.path.join(master_base_dir, "master-config.yaml") + node_cfg_file = "node-config.yaml" + node_cfg = os.path.join(node_base_dir, node_cfg_file) + admin_cfg = os.path.join(master_base_dir, "admin.kubeconfig") + oc_cmd = "oc --config=%s" % admin_cfg + oadm_cmd = "oadm --config=%s" % admin_cfg + + files = (master_cfg, node_cfg) + + # Master vs. node + # + # OpenShift Origin/3.x cluster members can be a master, a node, or both at + # the same time: in most deployments masters are also nodes in order to get + # access to the pod network, which some functionality (e.g. the API proxy) + # requires. Therefore the following methods may all evaluate True on a + # single instance (at least one must evaluate True if this is an OpenShift + # installation) + def is_master(self): + '''Determine if we are on a master''' + return os.path.exists(self.master_cfg) + + def is_node(self): + '''Determine if we are on a node''' + return os.path.exists(self.node_cfg) + + def get_node_kubecfg(self): + '''Get the full path to the node's kubeconfig file + from the node's configuration''' + + # If we fail to find a specific kubeconfig we will + # just point to the general node configuration + kubeconfig = self.node_cfg_file + + # This should ideally use PyYAML to parse the node's + # configuration file, but PyYAML is currently not a + # dependency of sos and we can't guarantee it will + # be available, so this is a quick&dirty "grep" for + # the parameter we're looking for + cfgfile = open(self.node_cfg, 'r') + for line in cfgfile: + parts = line.split() + if len(parts) > 1 and parts[0] == 'masterKubeConfig:': + kubeconfig = parts[1] + break + cfgfile.close() + return os.path.join(self.node_base_dir, kubeconfig) + + def setup(self): + # Note that a system can run both a master and a node. + # See "Master vs. node" above. + if self.is_master(): + self.add_copy_spec([ + self.master_cfg, + os.path.join(self.master_base_dir, "*.crt"), + ]) + + # TODO: some thoughts about information that might also be + # useful to collect. However, the are maybe not needed in general + # and/or present some challenges (scale, sensitive, ...) and need + # some more thought. For now just leaving this comment here until + # we decide if it's worth collecting: + # + # General project status: + # oc status --all-namespaces (introduced in OSE 3.2) + # Metrics deployment configurations + # oc get -o json dc -n openshift-infra + # Logging stack deployment configurations + # oc get -o json dc -n logging + # + # Note: Information about nodes, events, pods, and services + # is already collected by the Kubernetes plugin + self.add_cmd_output([ + "%s describe projects" % self.oc_cmd, + "%s get -o json hostsubnet" % self.oc_cmd, + "%s get -o json clusternetwork" % self.oc_cmd, + "%s get -o json netnamespaces" % self.oc_cmd, + # Registry and router configs are typically here + "%s get -o json dc -n default" % self.oc_cmd, + "%s adm diagnostics -l 0 --config=%s" + % (self.oc_cmd, self.admin_cfg), + # Note: the diagnostics command was not available in earlier + # versions. OSE 3.1 had it as an ex[perimental] subcommand. + # If the above fails we could try this instead: + # "openshift ex diagnostics --config=%s" % self.admin_cfg, + # "openshift ex validate master-config %s" % self.master_cfg, + # We could do full version checks to act accordingly but + # the experimental versions are deprecated, so not worth it + ]) + self.add_journal(units=["atomic-openshift-master", + "atomic-openshift-master-api", + "atomic-openshift-master-controllers"]) + + # get logs from the infrastruture pods running in the default ns + pods = self.get_command_output("%s get pod -o name -n default" + % self.oc_cmd) + for pod in pods['output'].splitlines(): + self.add_cmd_output("%s logs -n default %s" + % (self.oc_cmd, pod)) + + # Note that a system can run both a master and a node. + # See "Master vs. node" above. + if self.is_node(): + self.add_copy_spec([ + self.node_cfg, + os.path.join(self.node_base_dir, "*.crt"), + ]) + + node_kubecfg = self.get_node_kubecfg() + self.add_cmd_output([ + "%s config view --config=%s" % (self.oc_cmd, node_kubecfg), + "%s diagnostics NodeConfigCheck --node-config=%s" + % (self.oadm_cmd, self.node_cfg) + ]) + self.add_journal(units="atomic-openshift-node") + + def postproc(self): + # Clear env values from objects that can contain sensitive data + # Sample JSON content: + # { + # "name": "MYSQL_PASSWORD", + # "value": "mypassword" + # }, + # This will mask values when the "name" looks susceptible of + # values worth obfuscating, i.e. if the name contains strings + # like "pass", "pwd", "key" or "token". + env_regexp = r'(?P<var>{\s*"name":\s*[^,]*' \ + r'(pass|pwd|key|token|cred|secret' \ + r'|PASS|PWD|KEY|TOKEN|CRED|SECRET)[^,]*,' \ + r'\s*"value":)[^}]*' + self.do_cmd_output_sub('oc*json', env_regexp, r'\g<var> "********"') + # LDAP identity provider + self.do_file_sub(self.master_cfg, + r"(bindPassword:\s*)(.*)", + r'\1"********"') + # github/google/OpenID identity providers + self.do_file_sub(self.master_cfg, + r"(clientSecret:\s*)(.*)", + r'\1"********"') + + +class AtomicOpenShift(OpenShiftOrigin, RedHatPlugin): + ''' OpenShift Enterprise / OpenShift Container Platform + ''' + + packages = ('atomic-openshift',) + +# vim: set et ts=4 sw=4 : |