def cascade_delete(resource, item): """Cascade DELETE. Hook to delete all objects, which have the 'cascade_delete' option set in the data_relation and relate to the object, which was just deleted. """ domain = current_app.config['DOMAIN'] deleted_id = item[domain[resource]['id_field']] for res, res_domain in domain.items(): # Filter schema of `res` to get all fields containing references # to the resource of the deleted item relations = ((field, field_def['data_relation']) for field, field_def in res_domain['schema'].items() if 'data_relation' in field_def and field_def['data_relation'].get('resource') == resource) for field, data_relation in relations: # All items in `res` with reference to the deleted item lookup = {field: deleted_id} with admin_permissions(): try: if data_relation.get('cascade_delete'): # Delete the item as well deleteitem_internal(res, concurrency_check=False, **lookup) else: # Don't delete, only remove reference patch_internal(res, payload={field: None}, concurrency_check=False, **lookup) except NotFound: pass
def on_updated_host(updates, original): """ Called by EVE HOOK (app.on_updated_host) After host updated, if host is a template, report value of fields updated on host used this template if host is not template, add or remove services templates if _templates changed :param updates: modified fields :type updates: dict :param original: original fields :type original: dict :return: None """ # pylint: disable=too-many-locals if g.get('ignore_hook_patch', False): g.ignore_hook_patch = False return if original['_is_template']: # We must update all host use this template host_db = current_app.data.driver.db['host'] hosts = host_db.find({'_templates': original['_id']}) for host in hosts: Template.update_host_use_template(host, updates) else: if '_templates'in updates and updates['_templates'] != original['_templates']: if original['_templates_with_services']: service_db = current_app.data.driver.db['service'] # Get all services of this host myservices = service_db.find({'_is_template': False, 'host': original['_id']}) myservices_template_id = [] myservices_bis = {} for myservice in myservices: myservices_template_id.append(myservice['_templates'][0]) myservices_bis[myservice['_templates'][0]] = myservice services = {} service_template_id = [] # loop on host templates and add into services the service are templates for hostid in updates['_templates']: services_template = service_db.find({'_is_template': True, 'host': hostid}) for srv in services_template: services[srv['name']] = Template.prepare_service_to_post(srv, original[ '_id']) service_template_id.append(services[srv['name']]['_templates'][0]) services_to_add = list(set(service_template_id) - set(myservices_template_id)) services_to_del = list(set(myservices_template_id) - set(service_template_id)) for (_, service) in iteritems(services): if service['_templates'][0] in services_to_add: post_internal('service', [service]) for template_id in services_to_del: if template_id in myservices_bis: lookup = {"_id": myservices_bis[template_id]['_id']} deleteitem_internal('service', False, False, **lookup)
def post_devices(registers: list): """ Main function for Register. For the given devices, POST the new ones. This method rollbacks the database when raising exceptions, like when no device has been POSTed. If the function is called by post_internal(), as the method keeps the reference of the passed in devices, the caller will see how their devices are replaced by the db versions, plus a 'new' property acting as a flag to indicate if the device is new or not. If a device exists, the input device is replaced by the version of the database, loosing any change the input device was introducing (except benchmarks, which are updated). See `_execute_register` for more info. :raise InnerRequestError: for any error provoked by a failure in the POST of a device (except if the device already existed). It carries the original error sent by the POST. :raise NoDevicesToProcess: Raised to avoid creating empty registers, that actually did not POST any device """ log = [] try: for register in registers: caller_device = register[ 'device'] # Keep the reference from where register['device'] points to _execute_register(caller_device, register.get('created'), log) register['device'] = caller_device['_id'] if 'components' in register: caller_components = register['components'] register['components'] = [] for component in caller_components: component['parent'] = caller_device['_id'] _execute_register(component, register.get('created'), log) if component[ 'new']: # todo put new in g., don't use device register['components'].append(component['_id']) if caller_device['new']: set_components(register) elif not register['components']: text = 'Device {} and components {} already exist.'.format( register['device'], register['components']) raise NoDevicesToProcess(text) else: add_components([ register ]) # The device is not new but we have new computers # Note that we only need to copy a place from the parent if this already existed if 'place' in caller_device: inherit_place(caller_device['place'], register['device'], register['components']) except Exception as e: for device in reversed(log): # Rollback deleteitem_internal(Naming.resource(device['@type']), device) raise e else: from ereuse_devicehub.resources.hooks import set_date set_date(None, registers) # Let's get the time AFTER creating the devices
def on_deleted_item_service(item): """Called by EVE HOOK (app.on_deleted_item_service) After deleted a template service, we delete all services are linked to this template :param item: service dict :type item: dict :return: None """ service_db = current_app.data.driver.db['service'] if item['_is_template']: services = service_db.find({'_templates': item['_id']}) for service in services: lookup = {"_id": service['_id']} deleteitem_internal('service', False, False, **lookup)
def on_delete_signup(token): """Endpoint to delete signups via email""" try: s = Signer(get_token_secret()) signup_id = ObjectId(s.unsign(token).decode('utf-8')) except BadSignature: return "Unknown token" deleteitem_internal('eventsignups', concurrency_check=False, **{current_app.config['ID_FIELD']: signup_id}) redirect_url = current_app.config.get('SIGNUP_DELETED_REDIRECT') if redirect_url: return redirect(redirect_url) else: return current_app.config['SIGNUP_DELETED_TEXT']
def on_delete_confirmed(token): try: s = URLSafeSerializer(get_token_secret()) signup_id = ObjectId(s.loads(token)) except BadSignature: return "Unknown token" deleteitem_internal('eventsignups', concurrency_check=False, **{current_app.config['ID_FIELD']: signup_id}) redirect_url = current_app.config.get('SIGNUP_DELETED_REDIRECT') if redirect_url: return redirect(redirect_url) else: return current_app.config['SIGNUP_DELETED_TEXT']
def on_deleted_item_service(item): """ Called by EVE HOOK (app.on_deleted_item_service) After deleted a template service, we delete all services are linked to this template :param item: service dict :type item: dict :return: None """ service_db = current_app.data.driver.db['service'] if item['_is_template']: services = service_db.find({'_templates': item['_id']}) for service in services: lookup = {"_id": service['_id']} deleteitem_internal('service', False, False, **lookup)
def create_user(username): melwin_user, _, _, status = getitem_internal(resource='melwin/users', **{'id': username}) if melwin_user and status == 200: try: user_response, _, _, user_code, header = post_internal(resource=app.globals['auth']['users_collection'], payl={'id': username}, skip_validation=True) except: app.logger.exception("503: Could not create (POST) new user %i" % username) return False try: auth_response, _, _, auth_code, header = post_internal(resource='users/auth', payl={'id': username, 'user': user_response['_id'], 'auth': {"token": "", "valid": ""}}, skip_validation=True) except: app.logger.exception("%i: Could not create (mongo insert) user %i auth item" % (auth_code, username)) return False # Verify both post's response codes if user_code == 201 and auth_code == 201: return True else: try: from eve.methods.delete import deleteitem_internal if '_id' in user_response: _, _, _, code = deleteitem_internal(resource=app.globals['auth']['users_collection'], concurrency_check=False, suppress_callbacks=True, **{'_id': user_response['_id']}) app.logger.info("Deleted user from users") if '_id' in auth_response: _, _, _, code = deleteitem_internal(resource='users/auth', concurrency_check=False, suppress_callbacks=True, **{'_id': auth_response['_id']}) app.logger.info("Deleted user from users_auth") except: app.logger.exception("Delete operation of user %i from users and users_auth but failed" % username) return False
def test_deleteitem_internal(self): # test that deleteitem_internal is available and working properly. with self.app.test_request_context(self.item_id_url): r, _, _, status = deleteitem_internal(self.known_resource, concurrency_check=False, **{"_id": self.item_id}) self.assert204(status) r = self.test_client.get(self.item_id_url) self.assert404(r.status_code)
def on_deleted_item(resource_name, item): if resource_name == 'attendances_tutors': # r = {'id': item['attendance']} # attendance, *_ = deleteitem_internal( 'attendances', *r) try: other_attendances_tutors, *_ = getitem( 'attendances_tutors', {'attendance': item['attendance']}) except NotFound as e: attendance, *_ = deleteitem_internal('attendances', id=item['attendance'])
def test_deleteitem_internal(self): # test that deleteitem_internal is available and working properly. with self.app.test_request_context(self.item_id_url): r, _, _, status = deleteitem_internal(self.known_resource, concurrency_check=False, **{'_id': self.item_id}) self.assert204(status) r = self.test_client.get(self.item_id_url) self.assert404(r.status_code)
def post_devices(registers: list): """ Main function for Register. For the given devices, POST the new ones. This method rollbacks the database when raising exceptions, like when no device has been POSTed. If the function is called by post_internal(), as the method keeps the reference of the passed in devices, the caller will see how their devices are replaced by the db versions, plus a 'new' property acting as a flag to indicate if the device is new or not. If a device exists, the input device is replaced by the version of the database, loosing any change the input device was introducing (except benchmarks, which are updated). See `_execute_register` for more info. :raise InnerRequestError: for any error provoked by a failure in the POST of a device (except if the device already existed). It carries the original error sent by the POST. :raise NoDevicesToProcess: Raised to avoid creating empty registers, that actually did not POST any device """ log = [] try: for register in registers: caller_device = register['device'] # Keep the reference from where register['device'] points to _execute_register(caller_device, register.get('created'), log) register['device'] = caller_device['_id'] if 'components' in register: caller_components = register['components'] register['components'] = [] for component in caller_components: component['parent'] = caller_device['_id'] _execute_register(component, register.get('created'), log) if component['new']: # todo put new in g., don't use device register['components'].append(component['_id']) if caller_device['new']: set_components(register) elif not register['components']: raise NoDevicesToProcess() except Exception as e: for device in reversed(log): # Rollback deleteitem_internal(Naming.resource(device['@type']), device) raise e else: from ereuse_devicehub.resources.hooks import set_date set_date(None, registers) # Let's get the time AFTER creating the devices
def test_deleteitem_internal(self): """Deleteitem internal should honor soft delete settings. """ # test that deleteitem_internal is available and working properly. with self.app.test_request_context(self.item_id_url): r, _, _, status = deleteitem_internal(self.known_resource, concurrency_check=False, **{"_id": self.item_id}) self.assert204(status) r = self.test_client.get(self.item_id_url) data, status = self.parse_response(r) self.assert404(status) self.assertEqual(data.get(self.deleted_field), True)
def test_deleteitem_internal(self): """Deleteitem internal should honor soft delete settings.""" # test that deleteitem_internal is available and working properly. with self.app.test_request_context(self.item_id_url): r, _, _, status = deleteitem_internal(self.known_resource, concurrency_check=False, **{"_id": self.item_id}) self.assert204(status) r = self.test_client.get(self.item_id_url) data, status = self.parse_response(r) self.assert404(status) self.assertEqual(data.get(self.deleted_field), True)
def delete_internal(self, resource: str, concurrency_check=False, suppress_callbacks=False, **lookup): """Workaround for Eve issue https://github.com/nicolaiarocci/eve/issues/810""" from eve.methods.delete import deleteitem_internal url = self.config['URLS'][resource] path = '%s/%s/%s' % (self.api_prefix, url, lookup['_id']) with self.__fake_request_url_rule('DELETE', path): return deleteitem_internal(resource, concurrency_check=concurrency_check, suppress_callbacks=suppress_callbacks, **lookup)[:4]
def cron_timeseries(): """ Cron used to add perfdata from retention to timeseries databases :return: None """ with app.test_request_context(): timeseriesretention_db = current_app.data.driver.db[ 'timeseriesretention'] if timeseriesretention_db.find().count() > 0: tsc = timeseriesretention_db.find({ 'for_graphite': True, 'for_influxdb': False }) for data in tsc: if not Timeseries.send_to_timeseries_graphite([data]): break lookup = {"_id": data['_id']} deleteitem_internal('timeseriesretention', False, False, **lookup) tsc = timeseriesretention_db.find({ 'for_graphite': False, 'for_influxdb': True }) for data in tsc: if not Timeseries.send_to_timeseries_influxdb([data]): break lookup = {"_id": data['_id']} deleteitem_internal('timeseriesretention', False, False, **lookup) tsc = timeseriesretention_db.find({ 'for_graphite': True, 'for_influxdb': True }) for data in tsc: graphite_serv = True influxdb_serv = True if not Timeseries.send_to_timeseries_graphite([data]): graphite_serv = False if not Timeseries.send_to_timeseries_influxdb([data]): influxdb_serv = False lookup = {"_id": data['_id']} if graphite_serv and influxdb_serv: deleteitem_internal('timeseriesretention', False, False, **lookup) elif graphite_serv and not influxdb_serv: patch_internal('timeseriesretention', {"for_graphite": False}, False, False, **lookup) elif influxdb_serv and not graphite_serv: patch_internal('timeseriesretention', {"for_influxdb": False}, False, False, **lookup)
def cron_timeseries(): """ Cron used to add perfdata from retention to timeseries databases :return: None """ with app.test_request_context(): timeseriesretention_db = current_app.data.driver.db['timeseriesretention'] if timeseriesretention_db.find().count() > 0: tsc = timeseriesretention_db.find({'for_graphite': True, 'for_influxdb': False}) for data in tsc: if not Timeseries.send_to_timeseries_graphite([data]): break lookup = {"_id": data['_id']} deleteitem_internal('timeseriesretention', False, False, **lookup) tsc = timeseriesretention_db.find({'for_graphite': False, 'for_influxdb': True}) for data in tsc: if not Timeseries.send_to_timeseries_influxdb([data]): break lookup = {"_id": data['_id']} deleteitem_internal('timeseriesretention', False, False, **lookup) tsc = timeseriesretention_db.find({'for_graphite': True, 'for_influxdb': True}) for data in tsc: graphite_serv = True influxdb_serv = True if not Timeseries.send_to_timeseries_graphite([data]): graphite_serv = False if not Timeseries.send_to_timeseries_influxdb([data]): influxdb_serv = False lookup = {"_id": data['_id']} if graphite_serv and influxdb_serv: deleteitem_internal('timeseriesretention', False, False, **lookup) elif graphite_serv and not influxdb_serv: patch_internal('timeseriesretention', {"for_graphite": False}, False, False, **lookup) elif influxdb_serv and not graphite_serv: patch_internal('timeseriesretention', {"for_influxdb": False}, False, False, **lookup)
def on_updated_host(updates, original): """ Called by EVE HOOK (app.on_updated_host) After host updated, if host is a template, report value of fields updated on host used this template if host is not template, add or remove services templates if _templates changed :param updates: modified fields :type updates: dict :param original: original fields :type original: dict :return: None """ # pylint: disable=too-many-locals if g.get('ignore_hook_patch', False): g.ignore_hook_patch = False return if original['_is_template']: # We must update all host use this template host_db = current_app.data.driver.db['host'] hosts = host_db.find({'_templates': original['_id']}) for host in hosts: Template.update_host_use_template(host, updates) else: if '_templates' in updates and updates['_templates'] != original[ '_templates']: if original['_templates_with_services']: service_db = current_app.data.driver.db['service'] # Get all services of this host myservices = service_db.find({ '_is_template': False, 'host': original['_id'] }) myservices_template_id = [] myservices_bis = {} for myservice in myservices: myservices_template_id.append( myservice['_templates'][0]) myservices_bis[myservice['_templates'][0]] = myservice services = {} service_template_id = [] # loop on host templates and add into services the service are templates for hostid in updates['_templates']: services_template = service_db.find({ '_is_template': True, 'host': hostid }) for srv in services_template: services[srv[ 'name']] = Template.prepare_service_to_post( srv, original['_id']) service_template_id.append( services[srv['name']]['_templates'][0]) services_to_add = list( set(service_template_id) - set(myservices_template_id)) services_to_del = list( set(myservices_template_id) - set(service_template_id)) for (_, service) in iteritems(services): if service['_templates'][0] in services_to_add: post_internal('service', [service]) for template_id in services_to_del: if template_id in myservices_bis: lookup = { "_id": myservices_bis[template_id]['_id'] } deleteitem_internal('service', False, False, **lookup)
def execute_delete(resource: str, identifier): """Executes DELETE to the same DeviceHub with a new connection.""" _, _, _, status = deleteitem_internal(resource, **{'_id': str(identifier)}) if status != 204: raise InnerRequestError(status, {})
def on_updated_host(updates, original): """Called by EVE HOOK (app.on_updated_host) After host updated, if host is a template, report value of fields updated on host used this template if host is not template, add or remove services templates if _templates changed :param updates: modified fields :type updates: dict :param original: original fields :type original: dict :return: None """ # pylint: disable=too-many-locals, too-many-nested-blocks if g.get('ignore_hook_patch', False): g.ignore_hook_patch = False return if original['_is_template']: # We must update all host using this template host_db = current_app.data.driver.db['host'] hosts = host_db.find({'_templates': original['_id']}) for host in hosts: Template.update_host_use_template(host, updates) else: if '_templates' in updates and updates['_templates'] != original[ '_templates']: if original['_templates_with_services']: service_db = current_app.data.driver.db['service'] # Get all the real services of this host myservices = service_db.find({ '_is_template': False, 'host': original['_id'] }) myservices_template_id = [] myservices_bis = {} for myservice in myservices: # Consider all the service templates... not only the first one! for template_srv in myservice['_templates']: myservices_template_id.append(template_srv) myservices_bis[template_srv] = myservice # Find services templates in the update services = Template.get_host_template_services( original, True, updates['_templates']) service_template_id = [] for service_name in services: service = services[service_name] for template_srv_id in service['_templates']: service_template_id.append(template_srv_id) # Compare servies to add/delete services_to_add = list( set(service_template_id) - set(myservices_template_id)) services_to_del = list( set(myservices_template_id) - set(service_template_id)) for service_name in services: service = services[service_name] for template_srv_id in service['_templates']: if template_srv_id in services_to_add: post_internal('service', [service]) for template_id in services_to_del: if template_id in myservices_bis: lookup = { "_id": myservices_bis[template_id]['_id'] } deleteitem_internal('service', False, False, **lookup)