Scout id_plugin that uses a Kubernetes configmap to store the install ID.

        :param scout: Scout instance that's calling the plugin
        :param app: Name of the application that's using Scout
        :param map_name: Optional ConfigMap name to use; defaults to "scout.config.$app"
        :param namespace: Optional Kubernetes namespace to use; defaults to "default"

        This plugin assumes that the KUBERNETES_SERVICE_{HOST,PORT,PORT_HTTPS}
        environment variables are set correctly, and it assumes the default Kubernetes
        namespace unless the 'namespace' keyword argument is used to select a different
        namespace.

        If KUBERNETES_ACCESS_TOKEN is set in the environment, use that for the apiserver
        access token -- otherwise, the plugin assumes that it's running in a Kubernetes
        pod and tries to read its token from /var/run/secrets.

def configmap_install_id_plugin(scout, app, map_name=None, namespace="default"):
        """
        Scout id_plugin that uses a Kubernetes configmap to store the install ID.

        :param scout: Scout instance that's calling the plugin
        :param app: Name of the application that's using Scout
        :param map_name: Optional ConfigMap name to use; defaults to "scout.config.$app"
        :param namespace: Optional Kubernetes namespace to use; defaults to "default"

        This plugin assumes that the KUBERNETES_SERVICE_{HOST,PORT,PORT_HTTPS}
        environment variables are set correctly, and it assumes the default Kubernetes
        namespace unless the 'namespace' keyword argument is used to select a different
        namespace.

        If KUBERNETES_ACCESS_TOKEN is set in the environment, use that for the apiserver
        access token -- otherwise, the plugin assumes that it's running in a Kubernetes
        pod and tries to read its token from /var/run/secrets.
        """

        plugin_response = None

        if not map_name:
            map_name = "scout.config.{0}".format(app)

        kube_host = os.environ.get('KUBERNETES_SERVICE_HOST', None)

        try:
            kube_port = int(os.environ.get('KUBERNETES_SERVICE_PORT', 443))
        except ValueError:
            scout.logger.debug("Scout: KUBERNETES_SERVICE_PORT isn't numeric, defaulting to 443")
            kube_port = 443

        kube_proto = "https" if (kube_port == 443) else "http"

        kube_token = os.environ.get('KUBERNETES_ACCESS_TOKEN', None)

        if not kube_host:
            # We're not running in Kubernetes. Fall back to the usual filesystem stuff.
            scout.logger.debug("Scout: no KUBERNETES_SERVICE_HOST, not running in Kubernetes")
            return None

        if not kube_token:
            try:
                kube_token = open("/var/run/secrets/kubernetes.io/serviceaccount/token", "r").read()
            except OSError:
                pass

        if not kube_token:
            # We're not running in Kubernetes. Fall back to the usual filesystem stuff.
            scout.logger.debug("Scout: not running in Kubernetes")
            return None

        # OK, we're in a cluster. Load our map.

        base_url = "%s://%s:%s" % (kube_proto, kube_host, kube_port)
        url_path = "api/v1/namespaces/%s/configmaps" % namespace
        auth_headers = { "Authorization": "Bearer " + kube_token }
        install_id = None

        cm_url = "%s/%s" % (base_url, url_path)
        fetch_url = "%s/%s" % (cm_url, map_name)

        scout.logger.debug("Scout: trying %s" % fetch_url)

        try:
            r = requests.get(fetch_url, headers=auth_headers, verify=False)

            if r.status_code == 200:
                # OK, the map is present. What do we see?
                map_data = r.json()

                if "data" not in map_data:
                    # This is "impossible".
                    scout.logger.error("Scout: no map data in returned map???")
                else:
                    map_data = map_data.get("data", {})
                    scout.logger.debug("Scout: configmap has map data %s" % json.dumps(map_data))

                    install_id = map_data.get("install_id", None)

                    if install_id:
                        scout.logger.debug("Scout: got install_id %s from map" % install_id)
                        plugin_response = { "install_id": install_id }
        except OSError as e:
            scout.logger.debug("Scout: could not read configmap (map %s, namespace %s): %s" % 
                               (map_name, namespace, e))

        if not install_id:
            # No extant install_id. Try to create a new one.
            install_id = str(uuid4())

            cm = {
                "apiVersion":"v1",
                "kind":"ConfigMap",
                "metadata":{
                    "name": map_name,
                    "namespace": namespace,
                },
                "data": {
                    "install_id": install_id
                }
            }

            scout.logger.debug("Scout: saving new install_id %s" % install_id)

            saved = False
            try:
                r = requests.post(cm_url, headers=auth_headers, verify=False, json=cm)

                if r.status_code == 201:
                    saved = True
                    scout.logger.debug("Scout: saved install_id %s" % install_id)

                    plugin_response = {
                        "install_id": install_id,
                        "new_install": True
                    }
                else:
                    scout.logger.error("Scout: could not save install_id: {0}, {1}".format(r.status_code, r.text))
            except OSError as e:
                logging.debug("Scout: could not write configmap (map %s, namespace %s): %s" % 
                              (map_name, namespace, e))

        scout.logger.debug("Scout: plugin_response %s" % json.dumps(plugin_response))
        return plugin_response