Repository: scaleoutsystems/fedn
Issue: Obsolete document modification functions in pymongo

**Severity**
- [ ] Critical/Blocker (select if the issue makes the application unusable or causes serious data loss)
- [ ] High (select if the issue affects a major feature and there is no workaround or the available workaround is very complex)
- [x] Medium (select if the issue affects a minor feature or affects a major feature but has an easy enough workaround to not cause any major inconvenience)
- [ ] Low (select if the issue doesn't significantly affect the user experience, like minor visual bugs)

**Describe the bug**
The mongo statestore does not work with the latest release of pymongo (v 4.0). Collection object does no longer have the function "update" and has been replaced by "update_one", "update_many", "replace_one" and "replace_many".

**Solution**
Change update function in MongoReducerStateStore and MongoTracer which comply with the latest pymongo release. 

**Reproduction Steps**
use latest reducer image or latest pymongo in native mode.


**Contact Details**
An e-mail address in case we need to contact you for further details regarding this issue.


Changed files:
fedn/fedn/clients/reducer/statestore/mongoreducerstatestore.py, fedn/fedn/common/tracer/mongotracer.py

diff --git a/fedn/fedn/clients/reducer/statestore/mongoreducerstatestore.py b/fedn/fedn/clients/reducer/statestore/mongoreducerstatestore.py
index 250cb14..6035e00 100644
--- a/fedn/fedn/clients/reducer/statestore/mongoreducerstatestore.py
+++ b/fedn/fedn/clients/reducer/statestore/mongoreducerstatestore.py
@@ -73,7 +73,7 @@ class MongoReducerStateStore(ReducerStateStore):
                             print("Setting filepath to {}".format(control['context']), flush=True)
                             # TODO Fix the ugly latering of indirection due to a bug in secure_filename returning an object with filename as attribute
                             # TODO fix with unboxing of value before storing and where consuming.
-                            self.control.config.update({'key': 'package'},
+                            self.control.config.update_one({'key': 'package'},
                                                        {'$set': {'filename': control['context']}}, True)
                         if "helper" in control:
                             # self.set_framework(control['helper'])
@@ -131,7 +131,7 @@ class MongoReducerStateStore(ReducerStateStore):
         """
         old_state = self.state.find_one({'state': 'current_state'})
         if old_state != state:
-            return self.state.update({'state': 'current_state'}, {'state': ReducerStateToString(state)}, True)
+            return self.state.update_one({'state': 'current_state'}, {'$set': {'state': ReducerStateToString(state)}}, True)
         else:
             print("Not updating state, already in {}".format(ReducerStateToString(state)))
 
@@ -141,8 +141,8 @@ class MongoReducerStateStore(ReducerStateStore):
         :param model_id:
         """
         from datetime import datetime
-        x = self.model.update({'key': 'current_model'}, {'$set': {'model': model_id}}, True)
-        self.model.update({'key': 'model_trail'}, {'$push': {'model': model_id, 'committed_at': str(datetime.now())}},
+        x = self.model.update_one({'key': 'current_model'}, {'$set': {'model': model_id}}, True)
+        self.model.update_one({'key': 'model_trail'}, {'$push': {'model': model_id, 'committed_at': str(datetime.now())}},
                           True)
 
     def get_first(self):
@@ -180,7 +180,7 @@ class MongoReducerStateStore(ReducerStateStore):
         :param config:
         """
         from datetime import datetime
-        x = self.control.config.update({'key': 'round_config'}, {'$set': config}, True)
+        x = self.control.config.update_one({'key': 'round_config'}, {'$set': config}, True)
 
     def get_round_config(self):
         """
@@ -202,8 +202,8 @@ class MongoReducerStateStore(ReducerStateStore):
         :param filename:
         """
         from datetime import datetime
-        x = self.control.config.update({'key': 'package'}, {'$set': {'filename': filename}}, True)
-        self.control.config.update({'key': 'package_trail'},
+        x = self.control.config.update_one({'key': 'package'}, {'$set': {'filename': filename}}, True)
+        self.control.config.update_one({'key': 'package_trail'},
                                    {'$push': {'filename': filename, 'committed_at': str(datetime.now())}}, True)
 
     def get_compute_context(self):
@@ -225,7 +225,7 @@ class MongoReducerStateStore(ReducerStateStore):
 
         :param helper:
         """
-        self.control.config.update({'key': 'package'},
+        self.control.config.update_one({'key': 'package'},
                                    {'$set': {'helper': helper}}, True)
 
     def get_framework(self):
@@ -282,13 +282,13 @@ class MongoReducerStateStore(ReducerStateStore):
         config = copy.deepcopy(config)
         config['updated_at'] = str(datetime.now())
         config['status'] = 'enabled'
-        ret = self.storage.update({'storage_type': config['storage_type']}, config, True)
+        ret = self.storage.update_one({'storage_type': config['storage_type']}, {'$set': config}, True)
 
     def set_reducer(self, reducer_data):
         """ """
         from datetime import datetime
         reducer_data['updated_at'] = str(datetime.now())
-        ret = self.reducer.update({'name': reducer_data['name']}, reducer_data, True)
+        ret = self.reducer.update_one({'name': reducer_data['name']}, {'$set': reducer_data}, True)
 
     def get_reducer(self):
         """ """
@@ -329,7 +329,7 @@ class MongoReducerStateStore(ReducerStateStore):
         """
         from datetime import datetime
         combiner_data['updated_at'] = str(datetime.now())
-        ret = self.combiners.update({'name': combiner_data['name']}, combiner_data, True)
+        ret = self.combiners.update_one({'name': combiner_data['name']}, {'$set': combiner_data}, True)
 
     def delete_combiner(self, combiner):
         """ """
@@ -345,7 +345,7 @@ class MongoReducerStateStore(ReducerStateStore):
         """
         from datetime import datetime
         client_data['updated_at'] = str(datetime.now())
-        ret = self.clients.update({'name': client_data['name']}, client_data, True)
+        ret = self.clients.update_one({'name': client_data['name']}, {'$set': client_data}, True)
 
     def get_client(self, name):
         """ """
diff --git a/fedn/fedn/common/tracer/mongotracer.py b/fedn/fedn/common/tracer/mongotracer.py
index c56d9f6..21e088b 100644
--- a/fedn/fedn/common/tracer/mongotracer.py
+++ b/fedn/fedn/common/tracer/mongotracer.py
@@ -95,8 +95,8 @@ class MongoTracer(Tracer):
         :param round:
         :param round_time:
         """
-        self.round_time.update({'key': 'round_time'}, {'$push': {'round': round}}, True)
-        self.round_time.update({'key': 'round_time'}, {'$push': {'round_time': round_time}}, True)
+        self.round_time.update_one({'key': 'round_time'}, {'$push': {'round': round}}, True)
+        self.round_time.update_one({'key': 'round_time'}, {'$push': {'round_time': round_time}}, True)
 
     def set_combiner_time(self, round, round_time):
         """
@@ -104,8 +104,8 @@ class MongoTracer(Tracer):
         :param round:
         :param round_time:
         """
-        self.combiner_round_time.update({'key': 'combiner_round_time'}, {'$push': {'round': round}}, True)
-        self.combiner_round_time.update({'key': 'combiner_round_time'}, {'$push': {'round_time': round_time}}, True)
+        self.combiner_round_time.update_one({'key': 'combiner_round_time'}, {'$push': {'round': round}}, True)
+        self.combiner_round_time.update_one({'key': 'combiner_round_time'}, {'$push': {'round_time': round_time}}, True)
 
     # def set_combiner_queue_length(self,timestamp,ql):
     #    self.combiner_queue_length({'key': 'combiner_queue_length'}, {'$push': {'queue_length': ql}}, True)
@@ -117,14 +117,14 @@ class MongoTracer(Tracer):
 
         :param round_meta:
         """
-        self.round.update({'key': str(round_meta['round_id'])}, {'$push': {'combiners': round_meta}}, True)
+        self.round.update_one({'key': str(round_meta['round_id'])}, {'$push': {'combiners': round_meta}}, True)
 
     def set_round_meta_reducer(self, round_meta):
         """
 
         :param round_meta:
         """
-        self.round.update({'key': str(round_meta['round_id'])}, {'$push': {'reducer': round_meta}}, True)
+        self.round.update_one({'key': str(round_meta['round_id'])}, {'$push': {'reducer': round_meta}}, True)
 
     def get_latest_round(self):
         """
@@ -149,10 +149,10 @@ class MongoTracer(Tracer):
             mem_percents = currentProcess.memory_percent()
             ps_time = str(datetime.now())
 
-            self.psutil_monitoring.update({'key': 'cpu_mem_usage'}, {'$push': {'cpu': cpu_percents}}, True)
-            self.psutil_monitoring.update({'key': 'cpu_mem_usage'}, {'$push': {'mem': mem_percents}}, True)
-            self.psutil_monitoring.update({'key': 'cpu_mem_usage'}, {'$push': {'time': ps_time}}, True)
-            self.psutil_monitoring.update({'key': 'cpu_mem_usage'}, {'$push': {'round': round}}, True)
+            self.psutil_monitoring.update_one({'key': 'cpu_mem_usage'}, {'$push': {'cpu': cpu_percents}}, True)
+            self.psutil_monitoring.update_one({'key': 'cpu_mem_usage'}, {'$push': {'mem': mem_percents}}, True)
+            self.psutil_monitoring.update_one({'key': 'cpu_mem_usage'}, {'$push': {'time': ps_time}}, True)
+            self.psutil_monitoring.update_one({'key': 'cpu_mem_usage'}, {'$push': {'round': round}}, True)
 
     def start_monitor(self, round=None):
         """