Exemple #1
0
def write_last_known_good_stats_cache(stats, config_cache):
    logger.debug("Writing munin cache to %s" % config_cache)
    try:
        file(config_cache, 'w+').write(json.dumps(stats))
    except Exception, e:
        logger.error("Error writing munin config cache to %s: %s",
                     (config_cache, e))
Exemple #2
0
def get_stats(action, client, config):
    # place to store last known good statistics result to be used for munin
    # config when the app is down or b0rked
    options = config.get_munin_options()
    config_cache = options.get(
        'config_cache',
        os.path.join(config.get_default_dotm2ee_directory(),
                     'munin-cache.json'))

    # TODO: even better error/exception handling
    stats = None
    java_version = None
    try:
        stats, java_version = get_stats_from_runtime(client, config)
        write_last_known_good_stats_cache(stats, config_cache)
    except Exception, e:
        if action == 'config':
            logger.debug("Error fetching runtime/server statstics: %s", e)
            stats = read_stats_from_last_known_good_stats_cache(config_cache)
            if stats is None:
                stats = default_stats
        else:
            # assume something bad happened, like
            # socket.error: [Errno 111] Connection refused
            logger.error("Error fetching runtime/server statstics: %s", e)
def write_last_known_good_stats_cache(stats, config_cache):
    logger.debug("Writing munin cache to %s" % config_cache)
    try:
        file(config_cache, 'w+').write(json.dumps(stats))
    except Exception, e:
        logger.error("Error writing munin config cache to %s: %s",
                     (config_cache, e))
Exemple #4
0
    def do_show_debugger_status(self, args):
        if self._report_not_running():
            return

        m2eeresp = self.m2ee.client.get_debugger_status()
        if m2eeresp.get_result() == m2eeresp.ERR_ACTION_NOT_FOUND:
            logger.error("This action is not available in the Mendix Runtime "
                         "version you are currently using.")
            logger.error("It was implemented in Mendix 4.3.0")
            return
        if not m2eeresp.has_error():
            enabled = m2eeresp.get_feedback()['enabled']
            connected = m2eeresp.get_feedback()['client_connected']
            paused = m2eeresp.get_feedback()['number_of_paused_microflows']

            logger.info("The remote debugger is currently %s." %
                        ("enabled" if enabled else "disabled"))
            if connected:
                logger.info("A debugger session is connected.")
            elif enabled:
                logger.info("There is no connected debugger session.")
            if enabled and paused == 0:
                logger.info("There are no paused microflows.")
            elif paused == 1:
                logger.info("There is 1 paused microflow.")
            elif paused > 1:
                logger.info("There are %s paused microflows." % paused)
        else:
            m2eeresp.display_error()
Exemple #5
0
    def do_enable_debugger(self, args):
        if self._report_not_running():
            return

        if not args:
            debugger_password = raw_input(
                "Please enter the password to be used for remote debugger "
                "access from the modeler, or leave blank to auto-generate "
                "a password: "******"This action is not available in the Mendix Runtime "
                         "version you are currently using.")
            logger.error("It was implemented in Mendix 4.3.0")
            return
        m2eeresp.display_error()
        if not m2eeresp.has_error():
            logger.info("The remote debugger is now enabled, the password to "
                        "use is %s" % debugger_password)
            logger.info("You can use the remote debugger option in the Mendix "
                        "Business Modeler to connect to the /debugger/ sub "
                        "url on your application (e.g. "
                        "https://app.example.com/debugger/). ")
Exemple #6
0
 def do_activate_license(self, args):
     if self._report_not_running():
         return
     print("The command activate_license will set the license key used in "
           "this application. As far as currently known, recent Mendix "
           "Runtime versions do not check the submitted license key for "
           "validity, so incorrect input will unconditionally un-license "
           "your Mendix application! After setting the license, there will "
           "be no feedback about validity of the license. You can use show_"
           "license_information to check the active license. Also... after "
           "setting the license you will need to restart the application "
           "again to be sure it is fully activated.")
     answer = raw_input("Do you want to continue anyway? (type YES if you "
                        "want to): ")
     if answer != 'YES':
         print("Aborting.")
         return
     if not args:
         license_key = raw_input("Paste your license key (a long text "
                                 "string without newlines line): ")
     else:
         license_key = args
     m2eeresp = self.m2ee.client.set_license({'license_key': license_key})
     if m2eeresp.get_result() == m2eeresp.ERR_ACTION_NOT_FOUND:
         logger.error("This action is not available in the Mendix Runtime "
                      "version you are currently using.")
         logger.error("It was implemented in Mendix 3.0.0")
         return
     m2eeresp.display_error()
Exemple #7
0
 def do_check_health(self, args):
     if self._report_not_running():
         return
     health_response = self.m2ee.client.check_health()
     if not health_response.has_error():
         feedback = health_response.get_feedback()
         if feedback['health'] == 'healthy':
             logger.info("Health check microflow says the application is "
                         "healthy.")
         elif feedback['health'] == 'sick':
             logger.warning("Health check microflow says the application "
                            "is sick: %s" % feedback['diagnosis'])
         elif feedback['health'] == 'unknown':
             logger.info("Health check microflow is not configured, no "
                         "health information available.")
         else:
             logger.error("Unexpected health check status: %s" %
                          feedback['health'])
     else:
         if (health_response.get_result() == 3 and
                 health_response.get_cause() == "java.lang.IllegalArgument"
                 "Exception: Action should not be null"):
             # Because of an incomplete implementation, in Mendix 2.5.4 or
             # 2.5.5 this means that the runtime is health-check
             # capable, but no health check microflow is defined.
             logger.info("Health check microflow is probably not "
                         "configured, no health information available.")
         elif (health_response.get_result() ==
               health_response.ERR_ACTION_NOT_FOUND):
             logger.info("The Mendix version you are running does not yet "
                         "support health check functionality.")
         else:
             health_response.display_error()
Exemple #8
0
 def do_unpack(self, args):
     if not args:
         logger.error("unpack needs the name of a model upload zipfile in "
                      "%s as argument" %
                      self.m2ee.config.get_model_upload_path())
         return
     (pid_alive, m2ee_alive) = self.m2ee.check_alive()
     if pid_alive or m2ee_alive:
         logger.error("The application process is still running, refusing "
                      "to unpack a new application model right now.")
         return
     if mdautil.unpack(
         self.m2ee.config.get_model_upload_path(),
         args,
         self.m2ee.config.get_app_base(),
     ):
         self.m2ee.reload_config()
     post_unpack_hook = self.m2ee.config.get_post_unpack_hook()
     if post_unpack_hook:
         if os.path.isfile(post_unpack_hook):
             if os.access(post_unpack_hook, os.X_OK):
                 logger.info("Running post-unpack-hook...")
                 retcode = subprocess.call((post_unpack_hook,))
                 if retcode != 0:
                     logger.error("The post-unpack-hook returned a "
                                  "non-zero exit code: %d" % retcode)
             else:
                 logger.error("post-unpack-hook script %s is not "
                              "executable." % post_unpack_hook)
         else:
             logger.error("post-unpack-hook script %s does not exist." %
                          post_unpack_hook)
Exemple #9
0
def write_last_known_good_stats_cache(stats, config_cache):
    logger.debug("Writing munin cache to %s" % config_cache)
    try:
        with open(config_cache, "w+") as f:
            f.write(json.dumps(stats))
    except Exception as e:
        logger.error("Error writing munin config cache to %s: %s",
                     config_cache, e)
Exemple #10
0
 def do_psql(self, args):
     if not self.m2ee.config.is_using_postgresql():
         logger.error("Only PostgreSQL databases are supported right now.")
         return
     pgutil.psql(
         self.m2ee.config.get_pg_environment(),
         self.m2ee.config.get_psql_binary(),
     )
Exemple #11
0
 def _ask_user_to_fix_constants(self):
     answer = None
     logger.error("You'll have to add the constant definitions to the "
                  "configuration in the MicroflowConstants section.")
     while not answer in ('r', 'a'):
         answer = raw_input("Do you want to (r)etry, or (a)bort: ")
         if answer not in ('a', 'r'):
             print("Unknown option %s" % answer)
     return answer
Exemple #12
0
def read_stats_from_last_known_good_stats_cache(config_cache):
    stats = None
    logger.debug("Loading munin cache from %s" % config_cache)
    try:
        fd = open(config_cache)
        stats = json.loads(fd.read())
        fd.close()
    except IOError, e:
        logger.error("Error reading munin cache file %s: %s" %
                     (config_cache, e))
def read_stats_from_last_known_good_stats_cache(config_cache):
    stats = None
    logger.debug("Loading munin cache from %s" % config_cache)
    try:
        fd = open(config_cache)
        stats = json.loads(fd.read())
        fd.close()
    except IOError, e:
        logger.error("Error reading munin cache file %s: %s" %
                     (config_cache, e))
Exemple #14
0
    def _stop(self):
        (pid_alive, m2ee_alive) = self.m2ee.check_alive()
        if not pid_alive and not m2ee_alive:
            logger.info("Nothing to stop, the application is not running.")
            return True

        logger.debug("Trying to stop the application.")
        stopped = False

        logger.info("Waiting for the application to shutdown...")
        stopped = self.m2ee.runner.stop(timeout=10)
        if stopped:
            logger.info("The application has been stopped successfully.")
            return True

        logger.warn("The application did not shutdown by itself yet...")
        answer = None
        while not answer in ('y', 'n'):
            answer = raw_input("Do you want to try to signal the JVM "
                               "process to stop immediately? (y)es, (n)o? ")
            if answer == 'y':
                logger.info("Waiting for the JVM process to disappear...")
                stopped = self.m2ee.runner.terminate(timeout=10)
                if stopped:
                    logger.info("The JVM process has been stopped.")
                    return True
            elif answer == 'n':
                logger.info("Doing nothing, use stop again to check if the "
                            "process finally disappeared...")
                return False
            else:
                print("Unknown option %s" % answer)

        logger.warn("The application process seems not to respond to any "
                    "command or signal.")
        answer = None
        while not answer in ('y', 'n'):
            answer = raw_input("Do you want to kill the JVM process? (y)es,"
                               "(n)o? ")
            if answer == 'y':
                logger.info("Waiting for the JVM process to disappear...")
                stopped = self.m2ee.runner.kill(timeout=10)
                if stopped:
                    logger.info("The JVM process has been destroyed.")
                    return True
            elif answer == 'n':
                logger.info("Doing nothing, use stop again to check if the "
                            "process finally disappeared...")
                return False
            else:
                print("Unknown option %s" % answer)

        logger.error("Stopping the application process failed thorougly.")
        return False
Exemple #15
0
    def do_disable_debugger(self, args):
        if self._report_not_running():
            return

        m2eeresp = self.m2ee.client.disable_debugger()
        if m2eeresp.get_result() == m2eeresp.ERR_ACTION_NOT_FOUND:
            logger.error("This action is not available in the Mendix Runtime "
                         "version you are currently using.")
            logger.error("It was implemented in Mendix 4.3.0")
            return
        if not m2eeresp.has_error():
            logger.info("The remote debugger is now disabled.")
        else:
            m2eeresp.display_error()
Exemple #16
0
 def do_show_all_thread_stack_traces(self, args):
     if self._report_not_running():
         return
     m2eeresp = self.m2ee.client.get_all_thread_stack_traces()
     if m2eeresp.get_result() == m2eeresp.ERR_ACTION_NOT_FOUND:
         logger.error("This action is not available in the Mendix Runtime "
                      "version you are currently using.")
         logger.error("It was implemented in Mendix 3.2.0")
         return
     m2eeresp.display_error()
     if not m2eeresp.has_error():
         feedback = m2eeresp.get_feedback()
         print("Current JVM Thread Stacktraces:")
         print(pprint.pprint(feedback))
Exemple #17
0
def print_all(client, config, options, name, print_config=False):

    if name == "":
        name = pwd.getpwuid(os.getuid())[0]

    if print_config:
        funcs = config_funcs
    else:
        funcs = values_funcs

    if options is None:
        options = {}
    # place to store last known good statistics result to be used for munin
    # config when the app is down or b0rked
    config_cache = options.get('config_cache', os.path.join(
        config.get_default_dotm2ee_directory(), 'munin-cache.json'))
    graph_total_named_users = options.get('graph_total_named_users', True)

    # TODO: even better error/exception handling
    stats = {}
    try:
        logger.debug("trying to fetch runtime/server statistics")
        m2eeresponse = client.runtime_statistics()
        if not m2eeresponse.has_error():
            stats.update(m2eeresponse.get_feedback())
        m2eeresponse = client.server_statistics()
        if not m2eeresponse.has_error():
            stats.update(m2eeresponse.get_feedback())
        if type(stats['requests']) == list:
            # convert back to normal, whraagh
            bork = {}
            for x in stats['requests']:
                bork[x['name']] = x['value']
            stats['requests'] = bork
        # write last-known-good stats to cache
        try:
            file(config_cache, 'w+').write(json.dumps(stats))
        except Exception, e:
            logger.error("Error writing munin config cache to %s: %s",
                         (config_cache, e))
    except Exception, e:
        # assume something bad happened, like
        # socket.error: [Errno 111] Connection refused
        logger.error("Error fetching runtime/server statstics: %s", e)
        if print_config:
            logger.debug("Loading munin cache from %s" % config_cache)
            fd = None
            try:
                fd = open(config_cache)
            except Exception, e:
                logger.error("Error reading munin cache file %s: %s" %
                             (config_cache, e))
                return
            try:
                stats = json.loads(fd.read())
                fd.close()
            except Exception, e:
                logger.error("Error parsing munin cache file %s: %s" %
                             (config_cache, e))
                return
Exemple #18
0
 def do_emptydb(self, args):
     if not self.m2ee.config.is_using_postgresql():
         logger.error("Only PostgreSQL databases are supported right now.")
         return
     if not self.m2ee.config.allow_destroy_db():
         logger.error("Destructive database operations are turned off.")
         return
     (pid_alive, m2ee_alive) = self.m2ee.check_alive()
     if pid_alive or m2ee_alive:
         logger.warn("The application process is still running, refusing "
                     "to empty the database right now.")
         return
     pgutil.emptydb(
         self.m2ee.config.get_pg_environment(),
         self.m2ee.config.get_psql_binary(),
     )
Exemple #19
0
    def do_status(self, args):
        if self._report_not_running():
            return
        feedback = self.m2ee.client.runtime_status().get_feedback()
        logger.info("The application process is running, the MxRuntime has "
                    "status: %s" % feedback['status'])

        critlist = self.m2ee.client.get_critical_log_messages()
        if len(critlist) > 0:
            logger.error("%d critical error(s) were logged. Use show_critical"
                         "_log_messages to view them." % len(critlist))

        max_show_users = 10
        total_users = self._who(max_show_users)
        if total_users > max_show_users:
            logger.info("Only showing %s logged in users. Use who to see a "
                        "complete list." % max_show_users)
Exemple #20
0
 def do_show_current_runtime_requests(self, args):
     if self._report_not_running():
         return
     m2eeresp = self.m2ee.client.get_current_runtime_requests()
     if m2eeresp.get_result() == m2eeresp.ERR_ACTION_NOT_FOUND:
         logger.error("This action is not available in the Mendix Runtime "
                      "version you are currently using.")
         logger.error("It was implemented in Mendix 2.5.8 and 3.1.0")
         return
     m2eeresp.display_error()
     if not m2eeresp.has_error():
         feedback = m2eeresp.get_feedback()
         if not feedback:
             logger.info("There are no currently running runtime requests.")
         else:
             print("Current running Runtime Requests:")
             print(yaml.safe_dump(feedback))
Exemple #21
0
 def do_show_license_information(self, args):
     if self._report_not_running():
         return
     m2eeresp = self.m2ee.client.get_license_information()
     if m2eeresp.get_result() == m2eeresp.ERR_ACTION_NOT_FOUND:
         logger.error("This action is not available in the Mendix Runtime "
                      "version you are currently using.")
         logger.error("It was implemented in Mendix 3.0.0")
         return
     m2eeresp.display_error()
     if not m2eeresp.has_error():
         feedback = m2eeresp.get_feedback()
         if 'license' in feedback:
             print(yaml.safe_dump(feedback['license'], allow_unicode=True))
         elif 'license_id' in feedback:
             print("Unlicensed environment.")
             print("Server ID: %s" % feedback['license_id'])
         else:
             print("Unlicensed environment.")
Exemple #22
0
 def do_interrupt_request(self, args):
     if self._report_not_running():
         return
     if args == "":
         logger.error("This function needs a request id as parameter")
         logger.error("Use show_current_runtime_requests to view currently "
                      "running requests")
         return
     m2eeresp = self.m2ee.client.interrupt_request({"request_id": args})
     if m2eeresp.get_result() == m2eeresp.ERR_ACTION_NOT_FOUND:
         logger.error("This action is not available in the Mendix Runtime "
                      "version you are currently using.")
         logger.error("It was implemented in Mendix 2.5.8 and 3.1.0")
         return
     m2eeresp.display_error()
     if not m2eeresp.has_error():
         feedback = m2eeresp.get_feedback()
         if feedback["result"] is False:
             logger.error("A request with ID %s was not found" % args)
         else:
             logger.info("An attempt to cancel the running action was "
                         "made.")
def get_stats(action, client, config):
    # place to store last known good statistics result to be used for munin
    # config when the app is down or b0rked
    options = config.get_munin_options()
    config_cache = options.get('config_cache',
                               os.path.join(config.get_default_dotm2ee_directory(),
                                            'munin-cache.json'))

    # TODO: even better error/exception handling
    stats = None
    try:
        stats = get_stats_from_runtime(client, config)
        write_last_known_good_stats_cache(stats, config_cache)
    except Exception, e:
        if action == 'config':
            logger.debug("Error fetching runtime/server statstics: %s", e)
            stats = read_stats_from_last_known_good_stats_cache(config_cache)
            if stats is None:
                stats = default_stats
        else:
            # assume something bad happened, like
            # socket.error: [Errno 111] Connection refused
            logger.error("Error fetching runtime/server statstics: %s", e)
Exemple #24
0
 def _ask_user_whether_to_create_db(self):
     answer = None
     while not answer in ('c', 'r', 'a'):
         if self.m2ee.config.get_dtap_mode()[0] in 'DT':
             answer = raw_input("Do you want to (c)reate, (r)etry, or "
                                "(a)bort: ")
         else:
             answer = raw_input("Do you want to (r)etry, or (a)bort: ")
         if answer in ('a', 'r'):
             pass
         elif answer == 'c':
             if not self.m2ee.config.get_dtap_mode()[0] in ('D', 'T'):
                 logger.error("Automatic Database creation is disabled in "
                              "Acceptance and Production mode!")
                 answer = None
             elif not self.m2ee.config.dirty_hack_is_25():
                 # If in Development/Test, call execute_ddl_commands,
                 # because since 3.0, this tries to create a database and
                 # immediately executes initial ddl commands
                 m2eeresponse = self.m2ee.client.execute_ddl_commands()
                 m2eeresponse.display_error()
         else:
             print("Unknown option %s" % answer)
     return answer
Exemple #25
0
 def do_restoredb(self, args):
     if not self.m2ee.config.is_using_postgresql():
         logger.error("Only PostgreSQL databases are supported right now.")
         return
     if not self.m2ee.config.allow_destroy_db():
         logger.error("Destructive database operations are turned off.")
         return
     if not args:
         logger.error("restoredb needs the name of a dump file in %s as arg"
                      "ument" % self.m2ee.config.get_database_dump_path())
         return
     (pid_alive, m2ee_alive) = self.m2ee.check_alive()
     if pid_alive or m2ee_alive:
         logger.warn("The application is still running, refusing to "
                     "restore the database right now.")
         return
     pgutil.restoredb(
         self.m2ee.config.get_pg_environment(),
         self.m2ee.config.get_pg_restore_binary(),
         self.m2ee.config.get_database_dump_path(),
         args,
     )
Exemple #26
0
    def _start_runtime(self):
        """
        This function deals with the start-up sequence of the Mendix Runtime.

        After a fixup of the mxclientsystem symlink, which needs to point to
        the right version of the mxclientsystem code, and submitting runtime
        configuration settings, the start action is called.

        Starting the Mendix Runtime can fail in both a temporary or permanent
        way.

        Known error codes are:
          2: Database to be used does not exist
          3: Database structure is out of sync with the application domain
             model, DDL commands need to be run to synchronize the database.
          4: Constant definitions used in the application model are missing
             from the configuration.
          5: In the application database, a user account was detected which
             has the administrative role (as specified in the modeler) and
             has password '1'.
          6: The Mendix Runtime has reached an invalid state and cannot start.
          7,8,9: Mandatory configuration items are missing.

        By using startresponse.display_error() the error message sent by the
        Mendix Runtime is printed. Temporary failures need to be resolved,
        often interactively.
        """
        self.m2ee.fix_mxclientsystem_symlink()

        if not self.m2ee.send_runtime_config():
            return

        abort = False
        fully_started = False
        params = {}
        while not (fully_started or abort):
            startresponse = self.m2ee.client.start(params)
            result = startresponse.get_result()
            if result == 0:
                fully_started = True
                logger.info("The MxRuntime is fully started now.")
            else:
                startresponse.display_error()
                if result == 2:
                    answer = self._ask_user_whether_to_create_db()
                    if answer == 'a':
                        abort = True
                    elif self.m2ee.config._dirty_hack_is_25 and answer == 'c':
                        params["autocreatedb"] = True
                elif result == 3:
                    answer = self._handle_ddl_commands()
                    if answer == 'a':
                        abort = True
                elif result == 4:
                    answer = self._ask_user_to_fix_constants()
                    if answer == 'a':
                        abort = True
                elif result == 5:
                    answer = self._handle_admin_1(
                        startresponse.get_feedback()['users'])
                    if answer == 'a':
                        abort = True
                elif result == 6:
                    abort = True
                elif result == 7 or result == 8 or result == 9:
                    logger.error("You'll have to fix the configuration and "
                                 "run start again... (or ask for help..)")
                    abort = True
                else:
                    abort = True

        if abort:
            self._stop()
        logger.error("Error writing munin config cache to %s: %s",
                     (config_cache, e))


def read_stats_from_last_known_good_stats_cache(config_cache):
    stats = None
    logger.debug("Loading munin cache from %s" % config_cache)
    try:
        fd = open(config_cache)
        stats = json.loads(fd.read())
        fd.close()
    except IOError, e:
        logger.error("Error reading munin cache file %s: %s" %
                     (config_cache, e))
    except ValueError, e:
        logger.error("Error parsing munin cache file %s: %s" %
                     (config_cache, e))
    return stats


def print_requests_config(name, stats):
    print("multigraph mxruntime_requests_%s" % name)
    print("graph_args --base 1000 -l 0")
    print("graph_vlabel Requests per second")
    print("graph_title %s - MxRuntime Requests" % name)
    print("graph_category Mendix")
    print("graph_info This graph shows the amount of requests this MxRuntime handles")
    for sub in stats['requests'].iterkeys():
        substrip = '_' + string.strip(sub, '/').replace('-', '_')
        if sub != '':
            subname = sub
        else:
Exemple #28
0
        logger.error("Error writing munin config cache to %s: %s",
                     (config_cache, e))


def read_stats_from_last_known_good_stats_cache(config_cache):
    stats = None
    logger.debug("Loading munin cache from %s" % config_cache)
    try:
        fd = open(config_cache)
        stats = json.loads(fd.read())
        fd.close()
    except IOError, e:
        logger.error("Error reading munin cache file %s: %s" %
                     (config_cache, e))
    except ValueError, e:
        logger.error("Error parsing munin cache file %s: %s" %
                     (config_cache, e))
    return stats


def print_requests_config(name, stats):
    print("multigraph mxruntime_requests_%s" % name)
    print("graph_args --base 1000 -l 0")
    print("graph_vlabel Requests per second")
    print("graph_title %s - MxRuntime Requests" % name)
    print("graph_category Mendix")
    print(
        "graph_info This graph shows the amount of requests this MxRuntime handles"
    )
    for sub in stats['requests'].iterkeys():
        substrip = '_' + string.strip(sub, '/').replace('-', '_')
        if sub != '':
Exemple #29
0
def _standardize_memory_pools_output(runtime_memory_pools, java_version):
    # type: (list[Mapping], int) -> Mapping[str, int]
    java_8_mapping = {
        "code": ("Code Cache", ),
        "permanent": ("Metaspace", ),
        "eden": ("Eden Space", ),
        "survivor": ("Survivor Space", ),
        "tenured": ("Tenured Gen", ),
    }
    java_11_mapping = {
        "code": (
            "CodeHeap 'non-nmethods'",
            "CodeHeap 'profiled nmethods'",
            "CodeHeap 'non-profiled nmethods'",
        ),
        "permanent": ("Metaspace", ),
        "eden": ("Eden Space", ),
        "survivor": ("Survivor Space", ),
        "tenured": ("Tenured Gen", ),
    }

    if java_version == 8:
        pool_mapping = java_8_mapping
    elif java_version == 11:
        pool_mapping = java_11_mapping
    else:
        # Why raise, instead of trying and "guess" based on known JVM/JREs?
        # Because the mapping has changed in every supported JRE. Better to
        # fail fast, so that mapping can be confirmed during testing of a new
        # JVM/JRE version.
        raise NotImplementedError(
            "Java version {} does not yet have a memorypool mapping in "
            "m2ee tools".format(java_version))

    # Transform memorypools from a list of dicts, to a dict of memory usages,
    # which is more what we want. Additionally ensure we use a standard pool
    # name. ie. For "PS Eden Space" use "Eden Space"
    memory_pools_dict = {
        _standard_pool_name(f["name"]): f["usage"]
        for f in runtime_memory_pools
    }

    output_stats = {}
    for our_memory_type, pool_names in pool_mapping.items():
        try:
            total = sum(
                [memory_pools_dict[pool_name] for pool_name in pool_names])
        except KeyError as exc:
            got_fields = list(memory_pools_dict.keys())
            required_fields = list(itertools.chain(*pool_mapping.values()))
            logger.error(
                "Collecting JVM memory pool stats failed. Memory pool "
                "output did not match expected output. Needed: %s. Got: %s",
                required_fields,
                got_fields,
            )
            raise RuntimeError("Unable to collect JVM memory pool stats. "
                               "Please contact support!") from exc
        output_stats[our_memory_type] = total

    return output_stats