Repository: mindsdb/mindsdb

Issue:
UUID endpoint
We need a UUID endpoint, say, `/api/config/reporting_uuid` that returns the mindsdb_native telemtry uuid to scout.

This will make less sense when/if mindsdb native starts wrapping over multiple machines running native, but we'll cross that bridge when we get there.

For now the impl is simple:

* When mindsdb starts create a predictor with a placeholder name
* Make the uuid endpoint call `.get_model_data` on that predictor and get the `report_uuid` key
* Send this key to the frontend in a json: `{"report_uuid": "{{value_of_the_report_uuid_key}}" }



Discussion:

Resolving patch:
diff --git a/mindsdb/api/http/namespaces/util.py b/mindsdb/api/http/namespaces/util.py
--- a/mindsdb/api/http/namespaces/util.py
+++ b/mindsdb/api/http/namespaces/util.py
@@ -1,5 +1,6 @@
 from flask import request
 from flask_restx import Resource, abort
+from flask import current_app as ca
 
 from mindsdb.api.http.namespaces.configs.util import ns_conf
 from mindsdb import __about__
@@ -11,25 +12,12 @@ def get(self):
         '''Checks server avaliable'''
         return {'status': 'ok'}
 
-
-@ns_conf.route('/shutdown')
-class Shutdown(Resource):
-    @ns_conf.doc('get_shutdown')
-    def get(self):
-        '''Shutdown server'''
-        if request.host.startswith('127.0.0.1') or request.host.startswith('localhost'):
-            func = request.environ.get('werkzeug.server.shutdown')
-            if func is None:
-                return '', 500
-            func()
-            return '', 200
-        abort(403, "")
-
-                
-@ns_conf.route('/util/version')
-class Version(Resource):
-    @ns_conf.doc('get_endpoint')
+@ns_conf.route('/report_uuid')
+class ReportUUID(Resource):
+    @ns_conf.doc('get_report_uuid')
     def get(self):
-        '''Check endpoint'''
-        return {'mindsdb': "{__about__.__version__}"}
-    
+        metamodel_name = '___monitroing_metamodel___'
+        predictor = ca.mindsdb_native.create(metamodel_name)
+        return {
+            'report_uuid': predictor.report_uuid
+        }
diff --git a/mindsdb/interfaces/native/mindsdb.py b/mindsdb/interfaces/native/mindsdb.py
--- a/mindsdb/interfaces/native/mindsdb.py
+++ b/mindsdb/interfaces/native/mindsdb.py
@@ -17,16 +17,24 @@ def __init__(self, config):
         self.config = config
         self.dbw = DatabaseWrapper(self.config)
 
+    def _setup_for_creation(self, name):
+            predictor_dir = Path(self.config.paths['predictors']).joinpath(name)
+            create_directory(predictor_dir)
+            versions_file_path = predictor_dir.joinpath('versions.json')
+            with open(str(versions_file_path), 'wt') as f:
+                json.dump(self.config.versions, f, indent=4, sort_keys=True)
+
+    def create(self, name):
+        self._setup_for_creation(name)
+        predictor = mindsdb_native.Predictor(name=name, run_env={'trigger': 'mindsdb'})
+        return predictor
+
     def learn(self, name, from_data, to_predict, kwargs={}):
         join_learn_process = kwargs.get('join_learn_process', False)
         if 'join_learn_process' in kwargs:
             del kwargs['join_learn_process']
 
-        predictor_dir = Path(self.config.paths['predictors']).joinpath(name)
-        create_directory(predictor_dir)
-        versions_file_path = predictor_dir.joinpath('versions.json')
-        with open(str(versions_file_path), 'wt') as f:
-            json.dump(self.config.versions, f, indent=4, sort_keys=True)
+        self._setup_for_creation(name)
 
         p = PredictorProcess(name, from_data, to_predict, kwargs, self.config.get_all(), 'learn')
         p.start()
@@ -43,7 +51,7 @@ def predict(self, name, when_data=None, kwargs={}):
         p.start()
         predictions = p.join()
         '''
-        mdb = mindsdb_native.Predictor(name=name)
+        mdb = mindsdb_native.Predictor(name=name, run_env={'trigger': 'mindsdb'})
 
         predictions = mdb.predict(
             when_data=when_data,
diff --git a/mindsdb/interfaces/native/predictor_process.py b/mindsdb/interfaces/native/predictor_process.py
--- a/mindsdb/interfaces/native/predictor_process.py
+++ b/mindsdb/interfaces/native/predictor_process.py
@@ -22,7 +22,7 @@ def run(self):
 
         name, from_data, to_predict, kwargs, config, trx_type = self._args
 
-        mdb = mindsdb_native.Predictor(name=name)
+        mdb = mindsdb_native.Predictor(name=name, run_env={'trigger': 'mindsdb'})
 
         if trx_type == 'learn':
             to_predict = to_predict if isinstance(to_predict, list) else [to_predict]


Test patch:
diff --git a/tests/docker/postgres/Dockerfile b/tests/docker/postgres/Dockerfile
--- a/tests/docker/postgres/Dockerfile
+++ b/tests/docker/postgres/Dockerfile
@@ -3,5 +3,6 @@ FROM postgres:12.3
 RUN apt-get update && apt-get install -y \
     postgresql-12-mysql-fdw
 
+
 RUN mkdir -p /docker-entrypoint-initdb.d && \
     echo 'CREATE EXTENSION mysql_fdw;' > /docker-entrypoint-initdb.d/init.sql
diff --git a/tests/integration_tests/api/test_http.py b/tests/integration_tests/api/test_http.py
--- a/tests/integration_tests/api/test_http.py
+++ b/tests/integration_tests/api/test_http.py
@@ -182,14 +182,29 @@ def test_5_datasource_not_found(self):
         response = requests.get(f'{root}/datasource/dummy_source')
         assert response.status_code == 404
 
-    def test_6_ping(self):
+    def test_6_utils(self):
         """
         Call utilities ping endpoint
         THEN check the response is success
+
+        Call utilities report_uuid endpoint
+        THEN check the response is success
+        THEN check if the report_uuid is present in the report json and well fromated
+        THEN Call the endpoint again and check that the two report_uuids returned match
         """
+
         response = requests.get(f'{root}/util/ping')
         assert response.status_code == 200
 
+        response = requests.get(f'{root}/util/report_uuid')
+        assert response.status_code == 200
+        report_uuid = response.json()['report_uuid']
+        assert report_uuid == 'no_report'
+
+        # Make sure the uuid doesn't change on subsequent requests
+        response = requests.get(f'{root}/util/report_uuid')
+        assert report_uuid == response.json()['report_uuid']
+
     def test_7_predictors(self):
         """
         Call list predictors endpoint
diff --git a/tests/integration_tests/flows/config/config.json b/tests/integration_tests/flows/config/config.json
--- a/tests/integration_tests/flows/config/config.json
+++ b/tests/integration_tests/flows/config/config.json
@@ -16,7 +16,7 @@
             "user": "mindsdb"
         }
     },
-    "config_version": "1.2",
+    "config_version": "1.3",
     "debug": true,
     "integrations": {
         "default_clickhouse": {
@@ -35,6 +35,23 @@
             "type": "mariadb",
             "user": "root"
         },
+        "default_mongodb": {
+            "enabled": false,
+            "host": "127.0.0.1",
+            "password": "",
+            "port": 27001,
+            "type": "mongodb",
+            "user": ""
+        },
+        "default_mssql": {
+            "enabled": true,
+            "host": "127.0.0.1",
+            "odbc_driver_name": "MySQL ODBC 8.0 Unicode Driver",
+            "password": "password",
+            "port": 1433,
+            "type": "mssql",
+            "user": "sa"
+        },
         "default_mysql": {
             "enabled": true,
             "host": "localhost",
@@ -44,57 +61,24 @@
             "user": "root"
         },
         "default_postgres": {
+            "database": "postgres",
             "enabled": true,
             "host": "localhost",
-            "user": "postgres",
             "password": "",
-            "database": "postgres",
             "port": 5432,
-            "type": "postgres"
-        },
-        "default_mssql": {
-            "enabled": true,
-            "host": "127.0.0.1",
-            "odbc_driver_name": "MySQL ODBC 8.0 Unicode Driver",
-            "password": "password",
-            "port": 1433,
-            "type": "mssql",
-            "user": "sa"
-        },
-        "default_mongodb": {
-            "enabled": false,
-            "host": "127.0.0.1",
-            "password": "",
-            "port": 27001,
-            "type": "mongodb",
-            "user": ""
+            "type": "postgres",
+            "user": "postgres"
         },
         "default_snowflake": {
             "enabled": false,
             "type": "snowflake"
         }
     },
-    "interface": {
-        "dataskillet": {
-            "enabled": false
-        },
-        "datastore": {
-            "enabled": true
-        },
-        "lightwood": {
-            "enabled": true
-        },
-        "mindsdb_native": {
-            "enabled": true
-        }
-    },
     "log": {
         "level": {
             "console": "WARNING",
             "file": "ERROR"
         }
     },
-    "pip_path": null,
-    "python_interpreter": null,
     "storage_dir": "/tmp/mindsdb_storage"
-}
+}
\ No newline at end of file