예제 #1
0
    def do_download_runtime(self, args):
        if args:
            try:
                mxversion = m2ee.version.MXVersion(args)
            except Exception:
                logger.error("The provided runtime version string is not a "
                             "valid Mendix Runtime version number. Try using "
                             "the format x.y.z, e.g. 4.7.1.")
                return
        else:
            mxversion = self.m2ee.config.get_runtime_version()

        if not mxversion:
            logger.info("You did not specify a Mendix Runtime version to "
                        "download, and no current unpacked application "
                        "model is available to determine the version from. "
                        "Specify a version number or use unpack first.")
            return

        version = str(mxversion)

        if self.m2ee.config.lookup_in_mxjar_repo(version):
            logger.info("The Mendix Runtime for version %s is already "
                        "installed. If you want to download another Runtime "
                        "version, specify the version number as argument to "
                        "download_runtime." % version)
            return

        if not self.m2ee.config.get_first_writable_mxjar_repo():
            logger.error("None of the locations specified in the mxjar_repo "
                         "configuration option are writable by the current "
                         "user account.")
            return

        self.m2ee.download_and_unpack_runtime(version)
예제 #2
0
    def do_download_runtime(self, args):
        if args:
            try:
                mxversion = m2ee.version.MXVersion(args)
            except Exception:
                logger.error("The provided runtime version string is not a "
                             "valid Mendix Runtime version number. Try using "
                             "the format x.y.z, e.g. 4.7.1.")
                return
        else:
            mxversion = self.m2ee.config.get_runtime_version()

        if not mxversion:
            logger.info("You did not specify a Mendix Runtime version to "
                        "download, and no current unpacked application "
                        "model is available to determine the version from. "
                        "Specify a version number or use unpack first.")
            return

        version = str(mxversion)

        if self.m2ee.config.lookup_in_mxjar_repo(version):
            logger.info("The Mendix Runtime for version %s is already "
                        "installed. If you want to download another Runtime "
                        "version, specify the version number as argument to "
                        "download_runtime." % version)
            return

        if not self.m2ee.config.get_first_writable_mxjar_repo():
            logger.error("None of the locations specified in the mxjar_repo "
                         "configuration option are writable by the current "
                         "user account.")
            return

        self.m2ee.download_and_unpack_runtime(version)
예제 #3
0
 def do_check_health(self, args):
     if self._report_not_implemented('2.5.4') or 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:
         runtime_version = self.m2ee.config.get_runtime_version()
         if (health_response.get_result() == 3
                 and runtime_version // ('2.5.4', '2.5.5')):
             # 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.")
         else:
             health_response.display_error()
예제 #4
0
def _write_http_output_config(http_config):
    logger.debug("writing http output config")
    if "url" not in http_config:
        logger.error("APPMETRICS_TARGET.url value is not defined in {}".format(
            _get_appmetrics_target()))
        return

    http_output = {
        "url": http_config["url"],
        "method": "POST",
        "data_format": "influx",
    }

    username = http_config.get("username")
    password = http_config.get("password")
    if username:
        # Workaround for https://github.com/influxdata/telegraf/issues/4544
        # http_output['username'] = username
        # http_output['password'] = password
        credentials = base64.b64encode(
            ("{}:{}".format(username, password)).encode()).decode("ascii")
        http_output["[outputs.http.headers]"] = {
            "Authorization": "Basic {}".format(credentials)
        }

    kpionly = http_config["kpionly"] if "kpionly" in http_config else True
    if kpionly:
        http_output["[outputs.http.tagpass]"] = {"KPI": ["true"]}

    _write_config("[[outputs.http]]", http_output)
예제 #5
0
def parse_headers():
    header_config = ""
    headers_from_json = {}

    # this is kept for X-Frame-Options backward compatibility
    x_frame_options = os.environ.get("X_FRAME_OPTIONS", "ALLOW")
    if x_frame_options != "ALLOW":
        headers_from_json["X-Frame-Options"] = x_frame_options

    headers_json = os.environ.get("HTTP_RESPONSE_HEADERS", "{}")

    try:
        headers_from_json.update(json.loads(headers_json))
    except Exception as e:
        logger.error(
            "Failed to parse HTTP_RESPONSE_HEADERS, due to invalid JSON string: '{}'"
            .format(headers_json),
            exc_info=True,
        )
        raise

    for header_key, header_value in headers_from_json.items():
        regEx = DEFAULT_HEADERS[header_key]
        if regEx and re.match(regEx, header_value):
            escaped_value = header_value.replace('"',
                                                 '\\"').replace("'", "\\'")
            header_config += "add_header {} '{}';\n".format(
                header_key, escaped_value)
            logger.debug("Added header {} to nginx config".format(header_key))
        else:
            logger.warning(
                "Skipping {} config, value '{}' is not valid".format(
                    header_key, header_value))

    return header_config
예제 #6
0
def enable_runtime_agent(m2ee):
    # check already configured
    if 0 in [
            v.find("-javaagent") for v in m2ee.config._conf["m2ee"]["javaopts"]
    ]:
        return

    if m2ee.config.get_runtime_version() >= 7.14:
        # This is a dirty way to make it self-service until we pick up DEP-59.
        # After DEP-59 we can pick this up from a dedicated env var.
        agent_config = ""
        if "MetricsAgentConfig" in m2ee.config._conf["mxruntime"]:
            v = m2ee.config._conf["mxruntime"]["MetricsAgentConfig"]
            try:
                json.loads(v)  # ensure that this contains valid json
                config_file_path = os.path.abspath(
                    ".local/MetricsAgentConfig.json")
                with open(config_file_path, "w") as fh:
                    fh.write(v)
                agent_config = "=config=" + config_file_path
            except ValueError:
                logger.error(
                    "Could not parse json from MetricsAgentConfig",
                    exc_info=True,
                )
        jar = os.path.abspath(
            ".local/datadog/mx-agent-assembly-0.1.1-SNAPSHOT.jar")
        m2ee.config._conf["m2ee"]["javaopts"].extend([
            "-javaagent:{}{}".format(jar, agent_config),
            "-Xbootclasspath/a:{}".format(jar),
        ])
        # if not explicitly set, default to statsd
        m2ee.config._conf["mxruntime"].setdefault("com.mendix.metrics.Type",
                                                  "statsd")
예제 #7
0
 def do_check_health(self, args):
     if self._report_not_implemented('2.5.4') or 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:
         runtime_version = self.m2ee.config.get_runtime_version()
         if (health_response.get_result() == 3
                 and runtime_version // ('2.5.4', '2.5.5')):
             # 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.")
         else:
             health_response.display_error()
    def get_database_jdbc_url(self):
        """Return the database jdbc url for the M2EE configuration"""
        url = self.credentials.get("url", "")
        pattern = r"jdbc:sap://(?P<host>[^:]+):(?P<port>[0-9]+)/?(?P<q>\?(?P<params>.*))?$"
        match = re.search(pattern, url)
        if match is None:
            logger.error("Unable to parse Hana JDBC url string for parameters")
            raise Exception(
                "Unable to parse Hana JDBC url string for parameters"
            )

        parameters = {}
        if match.group("q") is not None and match.group("params") is not None:
            q = match.group("q")
            params = match.group("params")
            parameters.update(parse_qs(params))

        # override parameters from DATABASE_CONNECTION_PARAMS
        parameters.update(self.get_override_connection_parameters())

        if q is not None and len(parameters) > 0:
            parameterStr = "?{}".format(urlencode(parameters, True))
            url = url.replace(q, parameterStr)

        return url
예제 #9
0
def _write_http_output_config(http_config):
    logger.debug('writing http output config')
    if 'url' not in http_config:
        logger.error('APPMETRICS_TARGET.url value is not defined in {}'.format(
            _get_appmetrics_target()))
        return

    http_output = {
        'url': http_config['url'],
        'method': 'POST',
        'data_format': 'influx'
    }

    username = http_config.get('username')
    password = http_config.get('password')
    if username:
        # Workaround for https://github.com/influxdata/telegraf/issues/4544
        # http_output['username'] = username
        # http_output['password'] = password
        credentials = base64.b64encode(
            ('{}:{}'.format(username, password)).encode()).decode('ascii')
        http_output['[outputs.http.headers]'] = {
            'Authorization': 'Basic {}'.format(credentials)
        }

    kpionly = http_config['kpionly'] if 'kpionly' in http_config else True
    if kpionly:
        http_output['[outputs.http.tagpass]'] = {'KPI': ['true']}

    _write_config('[[outputs.http]]', http_output)
예제 #10
0
def enable_runtime_agent(m2ee):
    # check already configured
    if 0 in [v.find('-javaagent') for v in m2ee.config._conf['m2ee']['javaopts']]:
        return

    if m2ee.config.get_runtime_version() >= 7.14:
        # This is a dirty way to make it self-service until we pick up DEP-59.
        # After DEP-59 we can pick this up from a dedicated env var.
        agent_config = ''
        if 'MetricsAgentConfig' in m2ee.config._conf['mxruntime']:
            v = m2ee.config._conf['mxruntime']['MetricsAgentConfig']
            try:
                json.loads(v)  # ensure that this contains valid json
                config_file_path = os.path.abspath('.local/MetricsAgentConfig.json')
                with open(config_file_path, 'w') as fh:
                    fh.write(v)
                agent_config = '=config=' + config_file_path
            except ValueError:
                logger.error('Could not parse json from MetricsAgentConfig', exc_info=True)
        jar = os.path.abspath('.local/datadog/mx-agent-assembly-0.1.1-SNAPSHOT.jar')
        m2ee.config._conf['m2ee']['javaopts'].extend([
            '-javaagent:{}{}'.format(jar, agent_config),
            '-Xbootclasspath/a:{}'.format(jar),
        ])
        # if not explicitly set, default to statsd
        m2ee.config._conf['mxruntime'].setdefault(
            'com.mendix.metrics.Type', 'statsd'
        )
예제 #11
0
 def do_dumpdb(self, args):
     if not self.m2ee.config.is_using_postgresql():
         logger.error("Only PostgreSQL databases are supported right now.")
         return
     if len(args) > 0:
         pgutil.dumpdb(self.m2ee.config, args)
     else:
         pgutil.dumpdb(self.m2ee.config)
예제 #12
0
 def do_dumpdb(self, args):
     if not self.m2ee.config.is_using_postgresql():
         logger.error("Only PostgreSQL databases are supported right now.")
         return
     if len(args) > 0:
         pgutil.dumpdb(self.m2ee.config, args)
     else:
         pgutil.dumpdb(self.m2ee.config)
예제 #13
0
파일: m2ee.py 프로젝트: pommi/m2ee-tools
    def _start(self):
        """
        This function deals with the start-up sequence of the Mendix Runtime.
        Starting the Mendix Runtime can fail in both a temporary or permanent
        way. See the client_errno for possible error codes.
        """

        if not self.m2ee.config.get_runtime_path():
            logger.error("It appears that the Mendix Runtime version which "
                         "has to be used for your application is not present "
                         "yet.")
            logger.info("You can try downloading it using the "
                        "download_runtime command.")
            return

        if not self.m2ee.start_appcontainer():
            return

        if not self.m2ee.send_runtime_config():
            self._stop()
            return

        abort = False
        fully_started = False
        params = {}
        while not (fully_started or abort):
            startresponse = self.m2ee.start_runtime(params)
            result = startresponse.get_result()
            if result == client_errno.SUCCESS:
                fully_started = True
            else:
                startresponse.display_error()
                if result == client_errno.start_NO_EXISTING_DB:
                    answer = self._ask_user_whether_to_create_db()
                    if answer == 'a':
                        abort = True
                    elif (self.m2ee.config.get_runtime_version() // 2.5 and
                          answer == 'c'):
                        params["autocreatedb"] = True
                elif result == client_errno.start_INVALID_DB_STRUCTURE:
                    answer = self._handle_ddl_commands()
                    if answer == 'a':
                        abort = True
                elif result == client_errno.start_MISSING_MF_CONSTANT:
                    logger.error("You'll have to add the constant definitions "
                                 "to the configuration in the "
                                 "MicroflowConstants section.")
                    abort = True
                elif result == client_errno.start_ADMIN_1:
                    answer = self._handle_admin_1(
                        startresponse.get_feedback()['users'])
                    if answer == 'a':
                        abort = True
                else:
                    abort = True

        if abort:
            self._stop()
예제 #14
0
def set_user_provided_java_options(m2ee_section):
    javaopts = m2ee_section["javaopts"]
    options = os.environ.get("JAVA_OPTS", None)
    if options:
        try:
            options = json.loads(options)
        except json.JSONDecodeError as e:
            logger.error(
                "Failed to parse JAVA_OPTS, due to invalid JSON.",
                exc_info=True,
            )
            raise
        javaopts.extend(options)
예제 #15
0
파일: m2ee.py 프로젝트: pommi/m2ee-tools
 def do_emptydb(self, args):
     if not self.m2ee.config.is_using_postgresql():
         logger.error("Only PostgreSQL databases are supported right now.")
         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
     logger.info("This command will drop all tables and sequences in "
                 "database %s." %
                 self.m2ee.config.get_pg_environment()['PGDATABASE'])
     answer = raw_input("Continue? (y)es, (N)o? ")
     if answer != 'y':
         print("Aborting!")
         return
     pgutil.emptydb(self.m2ee.config)
예제 #16
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)
예제 #17
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)
예제 #18
0
def enable_runtime_agent(m2ee):
    # check already configured
    if 0 in [
        v.find("-javaagent") for v in m2ee.config._conf["m2ee"]["javaopts"]
    ]:
        return

    if m2ee.config.get_runtime_version() >= 7.14:
        agent_config = ""
        agent_config_str = None

        if "METRICS_AGENT_CONFIG" in os.environ:
            agent_config_str = os.environ.get("METRICS_AGENT_CONFIG")
        elif "MetricsAgentConfig" in m2ee.config._conf["mxruntime"]:
            logger.warn(
                "Passing MetricsAgentConfig with Mendix Custom Runtime Setting is deprecated. "
                + "Please use METRICS_AGENT_CONFIG as environment variable."
            )
            agent_config_str = m2ee.config._conf["mxruntime"][
                "MetricsAgentConfig"
            ]

        if agent_config_str:
            try:
                # ensure that this contains valid json
                json.loads(agent_config_str)
                config_file_path = os.path.abspath(
                    ".local/MetricsAgentConfig.json"
                )
                with open(config_file_path, "w") as fh:
                    fh.write(agent_config_str)
                agent_config = "=config=" + config_file_path
            except ValueError:
                logger.error(
                    "Could not parse json from MetricsAgentConfig",
                    exc_info=True,
                )
        jar = os.path.abspath(".local/datadog/{}".format(MX_AGENT_JAR))
        m2ee.config._conf["m2ee"]["javaopts"].extend(
            ["-javaagent:{}{}".format(jar, agent_config)]
        )
        # if not explicitly set, default to statsd
        m2ee.config._conf["mxruntime"].setdefault(
            "com.mendix.metrics.Type", "statsd"
        )
예제 #19
0
 def do_emptydb(self, args):
     if not self.m2ee.config.is_using_postgresql():
         logger.error("Only PostgreSQL databases are supported right now.")
         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
     logger.info("This command will drop all tables and sequences in "
                 "database %s." %
                 self.m2ee.config.get_pg_environment()['PGDATABASE'])
     answer = ('y'
               if self.yolo_mode else raw_input("Continue? (y)es, (N)o? "))
     if answer != 'y':
         print("Aborting!")
         return
     pgutil.emptydb(self.m2ee.config)
예제 #20
0
 def _report_not_implemented(self, avail_since):
     runtime_version = self.m2ee.config.get_runtime_version()
     if runtime_version is None:
         return False  # DUNNO
     if not runtime_version >= avail_since:
         logger.error("This action is not available in the Mendix Runtime "
                      "version you are currently using.")
         if isinstance(avail_since, tuple):
             if len(avail_since) > 2:
                 implemented_in = ('%s, %s and %s' %
                                   (', '.join(map(str, avail_since[:-2])),
                                    avail_since[-2], avail_since[-1]))
             else:
                 implemented_in = '%s and %s' % avail_since
         else:
             implemented_in = avail_since
         logger.error("It was implemented in Mendix %s" % implemented_in)
         return True
     return False
예제 #21
0
파일: m2ee.py 프로젝트: pommi/m2ee-tools
 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
     logger.info("This command will replace the contents of the model/ and "
                 "web/ locations, using the files extracted from the "
                 "archive")
     answer = raw_input("Continue? (y)es, (N)o? ")
     if answer != 'y':
         logger.info("Aborting!")
         return
     self.m2ee.unpack(args)
예제 #22
0
파일: m2ee.py 프로젝트: pommi/m2ee-tools
 def _report_not_implemented(self, avail_since):
     runtime_version = self.m2ee.config.get_runtime_version()
     if runtime_version is None:
         return False  # DUNNO
     if not runtime_version >= avail_since:
         logger.error("This action is not available in the Mendix Runtime "
                      "version you are currently using.")
         if isinstance(avail_since, tuple):
             if len(avail_since) > 2:
                 implemented_in = (
                     '%s, %s and %s' %
                     (', '.join(map(str, avail_since[:-2])),
                     avail_since[-2], avail_since[-1]))
             else:
                 implemented_in = '%s and %s' % avail_since
         else:
             implemented_in = avail_since
         logger.error("It was implemented in Mendix %s" % implemented_in)
         return True
     return False
예제 #23
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
     logger.info("This command will replace the contents of the model/ and "
                 "web/ locations, using the files extracted from the "
                 "archive")
     answer = ('y'
               if self.yolo_mode else raw_input("Continue? (y)es, (N)o? "))
     if answer != 'y':
         logger.info("Aborting!")
         return
     self.m2ee.unpack(args)
예제 #24
0
파일: m2ee.py 프로젝트: pommi/m2ee-tools
 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 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
     database_name = self.m2ee.config.get_pg_environment()['PGDATABASE']
     answer = raw_input("This command will restore this dump into database "
                        "%s. Continue? (y)es, (N)o? " % database_name)
     if answer != 'y':
         logger.info("Aborting!")
         return
     pgutil.restoredb(self.m2ee.config, args)
예제 #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 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
     database_name = self.m2ee.config.get_pg_environment()['PGDATABASE']
     answer = ('y' if self.yolo_mode else raw_input(
         "This command will restore this dump into database "
         "%s. Continue? (y)es, (N)o? " % database_name))
     if answer != 'y':
         logger.info("Aborting!")
         return
     pgutil.restoredb(self.m2ee.config, args)
예제 #26
0
 def _ask_user_whether_to_create_db(self):
     answer = None
     while answer not 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 self.m2ee.config.get_runtime_version() >= 3:
                 # 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
예제 #27
0
 def _ask_user_whether_to_create_db(self):
     answer = None
     while answer not 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 self.m2ee.config.get_runtime_version() >= 3:
                 # 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
예제 #28
0
 def do_interrupt_request(self, args):
     if (self._report_not_implemented(('2.5.8', 3.1))
             or 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})
     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.")
예제 #29
0
 def do_interrupt_request(self, args):
     if (self._report_not_implemented(('2.5.8', 3.1))
             or 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})
     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.")
예제 #30
0
        elif _signo == signal.SIGUSR2:
            emit(jvm={"ooms": 1.0})
        else:
            # Should not happen
            pass
        m2ee.stop()
        sys.exit(1)

    signal.signal(signal.SIGTERM, sigterm_handler)
    signal.signal(signal.SIGUSR1, sigusr_handler)
    signal.signal(signal.SIGUSR2, sigusr_handler)

    try:
        service_backups()
        set_up_nginx_files(m2ee)
        telegraf.run()
        datadog.run()
        complete_start_procedure_safe_to_use_for_restart(m2ee)
        set_up_instadeploy_if_deploy_password_is_set(m2ee)
        start_metrics(m2ee)
        start_logging_heartbeat()
        start_nginx()
        loop_until_process_dies(m2ee)
    except Exception:
        x = traceback.format_exc()
        logger.error("Starting app container failed: %s" % x)
        callback_url = os.environ.get("BUILD_STATUS_CALLBACK_URL")
        if callback_url:
            requests.put(callback_url, x)
        raise
예제 #31
0
    if os.getenv('CF_INSTANCE_INDEX') is None:
        logger.warning(
            'CF_INSTANCE_INDEX environment variable not found. Assuming '
            'responsibility for scheduled events execution and database '
            'synchronization commands.')
    pre_process_m2ee_yaml()
    activate_license()
    m2ee = set_up_m2ee_client(get_vcap_data())

    def sigterm_handler(_signo, _stack_frame):
        m2ee.stop()
        sys.exit(0)

    signal.signal(signal.SIGTERM, sigterm_handler)

    try:
        service_backups()
        set_up_nginx_files(m2ee)
        complete_start_procedure_safe_to_use_for_restart(m2ee)
        set_up_instadeploy_if_deploy_password_is_set(m2ee)
        start_metrics(m2ee)
        start_nginx()
        loop_until_process_dies(m2ee)
    except Exception:
        x = traceback.format_exc()
        logger.error('Starting app container failed: %s' % x)
        callback_url = os.environ.get('BUILD_STATUS_CALLBACK_URL')
        if callback_url:
            requests.put(callback_url, x)
        raise
예제 #32
0
def determine_cluster_redis_credentials():
    vcap_services = buildpackutil.get_vcap_services_data()
    if vcap_services and 'rediscloud' in vcap_services:
        return vcap_services['rediscloud'][0]['credentials']
    logger.error("Redis Cloud Service should be configured for this app")
    sys.exit(1)
예제 #33
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)
예제 #34
0
    def _start(self):
        """
        This function deals with the start-up sequence of the Mendix Runtime.
        Starting the Mendix Runtime can fail in both a temporary or permanent
        way. See the client_errno for possible error codes.
        """

        if not self.m2ee.config.get_runtime_path():
            logger.error("It appears that the Mendix Runtime version which "
                         "has to be used for your application is not present "
                         "yet.")
            logger.info("You can try downloading it using the "
                        "download_runtime command.")
            return

        if not self.m2ee.start_appcontainer():
            return

        database_password = None
        if not self.m2ee.config.has_database_password():
            database_password = getpass.getpass(
                "Database password not configured, "
                "please provide now:")
        if not self.m2ee.send_runtime_config(database_password):
            self._stop()
            return

        abort = False
        fully_started = False
        params = {}
        while not (fully_started or abort):
            startresponse = self.m2ee.start_runtime(params)
            result = startresponse.get_result()
            if result == client_errno.SUCCESS:
                fully_started = True
            else:
                startresponse.display_error()
                if result == client_errno.start_NO_EXISTING_DB:
                    answer = self._ask_user_whether_to_create_db()
                    if answer == 'a':
                        abort = True
                    elif (self.m2ee.config.get_runtime_version() // 2.5
                          and answer == 'c'):
                        params["autocreatedb"] = True
                elif result == client_errno.start_INVALID_DB_STRUCTURE:
                    answer = self._handle_ddl_commands()
                    if answer == 'a':
                        abort = True
                elif result == client_errno.start_MISSING_MF_CONSTANT:
                    logger.error("You'll have to add the constant definitions "
                                 "to the configuration in the "
                                 "MicroflowConstants section.")
                    abort = True
                elif result == client_errno.start_ADMIN_1:
                    users = startresponse.get_feedback()['users']
                    if self.yolo_mode:
                        self._handle_admin_1_yolo(users)
                    else:
                        answer = self._handle_admin_1(users)
                        if answer == 'a':
                            abort = True
                else:
                    abort = True

        if abort:
            self._stop()
예제 #35
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)
예제 #36
0
def update_config(m2ee, app_name):
    if not is_enabled():
        return
    tags = _get_tags()
    m2ee.config._conf['m2ee']['javaopts'].extend([
        '-Dcom.sun.management.jmxremote',
        '-Dcom.sun.management.jmxremote.port=7845',
        '-Dcom.sun.management.jmxremote.local.only=true',
        '-Dcom.sun.management.jmxremote.authenticate=false',
        '-Dcom.sun.management.jmxremote.ssl=false',
        '-Djava.rmi.server.hostname=127.0.0.1',
    ])
    if m2ee.config.get_runtime_version() >= 7.15:
        m2ee.config._conf['logging'].append({
            'type': 'tcpjsonlines',
            'name': 'DataDogSubscriber',
            'autosubscribe': 'INFO',
            'host': 'localhost',
            'port': 9032,
        })
    if m2ee.config.get_runtime_version() >= 7.14:
        # This is a dirty way to make it self-service until we pick up DEP-59.
        # After DEP-59 we can pick this up from a dedicated env var.
        agent_config = ''
        if 'MetricsAgentConfig' in m2ee.config._conf['mxruntime']:
            v = m2ee.config._conf['mxruntime']['MetricsAgentConfig']
            try:
                json.loads(v)  # ensure that this contains valid json
                config_file_path = os.path.abspath(
                    '.local/MetricsAgentConfig.json')
                with open(config_file_path, 'w') as fh:
                    fh.write(v)
                agent_config = '=config=' + config_file_path
            except ValueError:
                logger.error('Could not parse json from MetricsAgentConfig',
                             exc_info=True)
        jar = os.path.abspath(
            '.local/datadog/mx-agent-assembly-0.1.1-SNAPSHOT.jar')
        m2ee.config._conf['m2ee']['javaopts'].extend([
            '-javaagent:{}{}'.format(jar, agent_config),
            '-Xbootclasspath/a:{}'.format(jar),
        ])
        # if not explicitly set, default to statsd
        m2ee.config._conf['mxruntime'].setdefault('com.mendix.metrics.Type',
                                                  'statsd')
    subprocess.check_call(('mkdir', '-p', '.local/datadog'))
    with open('.local/datadog/datadog.yaml', 'w') as fh:
        config = {
            'dd_url': 'https://app.datadoghq.com',
            'api_key': None,  # set via DD_API_KEY instead
            'confd_path': '.local/datadog/conf.d',
            'logs_enabled': True,
            'log_file': '/dev/null',  # will be printed via stdout/stderr
            'hostname': _get_hostname(),
            'tags': tags,
            'process_config': {
                'enabled': 'true',  # has to be string
                'log_file': '/dev/null',
            },
            'apm_config': {
                'enabled': True,
                'max_traces_per_second': 10,
            },
            'logs_config': {
                'run_path': '.local/datadog/run',
            },
        }
        fh.write(yaml.safe_dump(config))
    subprocess.check_call(('mkdir', '-p', '.local/datadog/conf.d/mendix.d'))
    subprocess.check_call(('mkdir', '-p', '.local/datadog/run'))
    with open('.local/datadog/conf.d/mendix.d/conf.yaml', 'w') as fh:
        config = {
            'logs': [{
                'type': 'tcp',
                'port': '9032',
                'service': _get_service(),
                'source': 'mendix',
                'tags': tags,
            }],
        }
        fh.write(yaml.safe_dump(config))
    subprocess.check_call(('mkdir', '-p', '.local/datadog/conf.d/jmx.d'))
    with open('.local/datadog/conf.d/jmx.d/conf.yaml', 'w') as fh:
        # jmx beans and values can be inspected with jmxterm
        # download the jmxterm jar into the container
        # and run app/.local/bin/java -jar ~/jmxterm.jar
        #
        # the extra attributes are only available from Mendix 7.15.0+
        config = {
            'init_config': {
                'collect_default_metrics': True,
                'is_jmx': True,
            },
            'instances': [{
                'host':
                'localhost',
                'port':
                7845,
                'java_bin_path':
                '.local/bin/java',
                'java_options':
                '-Xmx50m -Xms5m',
                # 'refresh_beans': 10, # runtime takes time to initialize the beans
                'conf': [
                    {
                        'include': {
                            'bean': 'com.mendix:type=SessionInformation',
                            # NamedUsers = 1;
                            # NamedUserSessions = 0;
                            # AnonymousSessions = 0;
                            'attribute': {
                                'NamedUsers': {
                                    'metrics_type': 'gauge'
                                },
                                'NamedUserSessions': {
                                    'metrics_type': 'gauge'
                                },
                                'AnonymousSessions': {
                                    'metrics_type': 'gauge'
                                },
                            },
                        },
                    },
                    {
                        'include': {
                            'bean':
                            'com.mendix:type=Statistics,name=DataStorage',
                            # Selects = 1153;
                            # Inserts = 1;
                            # Updates = 24;
                            # Deletes = 0;
                            # Transactions = 25;
                            'attribute': {
                                'Selects': {
                                    'metrics_type': 'counter'
                                },
                                'Updates': {
                                    'metrics_type': 'counter'
                                },
                                'Inserts': {
                                    'metrics_type': 'counter'
                                },
                                'Deletes': {
                                    'metrics_type': 'counter'
                                },
                                'Transactions': {
                                    'metrics_type': 'counter'
                                },
                            },
                        },
                    },
                    {
                        'include': {
                            'bean': 'com.mendix:type=General',
                            # Languages = en_US;
                            # Entities = 24;
                            'attribute': {
                                'Entities': {
                                    'metrics_type': 'gauge'
                                },
                            },
                        },
                    },
                    {
                        'include': {
                            'bean': 'com.mendix:type=JettyThreadPool',
                            # Threads = 8
                            # IdleThreads = 3;
                            # IdleTimeout = 60000;
                            # MaxThreads = 254;
                            # StopTimeout = 30000;
                            # MinThreads = 8;
                            # ThreadsPriority = 5;
                            # QueueSize = 0;
                            'attribute': {
                                'Threads': {
                                    'metrics_type': 'gauge'
                                },
                                'MaxThreads': {
                                    'metrics_type': 'gauge'
                                },
                                'IdleThreads': {
                                    'metrics_type': 'gauge'
                                },
                                'QueueSize': {
                                    'metrics_type': 'gauge'
                                },
                            },
                        },
                    }
                ],
                #  }, {
                #    'include': {
                #        'bean': 'com.mendix:type=Jetty',
                #        # ConnectedEndPoints = 0;
                #        # IdleTimeout = 30000;
                #        # RequestsActiveMax = 0;

                #        'attribute': {
                #        }
                #    },
            }],
        }
        fh.write(yaml.safe_dump(config))

    _set_up_postgres()