def create_template(): try: init_tenant_context(request, db) tpl, json_payload = parse_payload(request, template_schema) loaded_template = DeviceTemplate(**tpl) load_attrs(json_payload['attrs'], loaded_template, DeviceAttr, db) db.session.add(loaded_template) try: db.session.commit() except IntegrityError as error: handle_consistency_exception(error) results = json.dumps({ 'template': template_schema.dump(loaded_template).data, 'result': 'ok' }) return make_response(results, 200) except HTTPRequestError as error: if isinstance(error.message, dict): return make_response(json.dumps(error.message), error.error_code) else: return format_response(error.error_code, error.message)
def update_template(templateid): try: init_tenant_context(request, db) # find old version of the template, if any old = assert_template_exists(templateid) # parse updated version from payload updated, json_payload = parse_payload(request, template_schema) old.label = updated['label'] for attr in old.attrs: db.session.delete(attr) for attr in json_payload['attrs']: mapped = DeviceAttr(template=old, **attr) db.session.add(mapped) try: db.session.commit() except IntegrityError as error: handle_consistency_exception(error) results = {'updated': template_schema.dump(old).data, 'result': 'ok'} return make_response(json.dumps(results), 200) except HTTPRequestError as error: if isinstance(error.message, dict): return make_response(json.dumps(error.message), error.error_code) else: return format_response(error.error_code, error.message)
def get_templates(): try: init_tenant_context(request, db) page_number, per_page = get_pagination(request) page = DeviceTemplate.query.paginate(page=int(page_number), per_page=int(per_page), error_out=False) templates = template_list_schema.dump(page.items).data result = { 'pagination': { 'page': page.page, 'total': page.pages, 'has_next': page.has_next, 'next_page': page.next_num }, 'templates': templates } attr_format(request, result) return make_response(json.dumps(result), 200) except HTTPRequestError as e: if isinstance(e.message, dict): return make_response(json.dumps(e.message), e.error_code) else: return format_response(e.error_code, e.message)
def get_by_template(templateid): try: init_tenant_context(request, db) page_number, per_page = get_pagination(request) page = ( db.session.query(Device) .join(DeviceTemplateMap) .filter_by(template_id=templateid) .paginate(page=page_number, per_page=per_page, error_out=False) ) devices = [] for d in page.items: devices.append(serialize_full_device(d)) result = json.dumps({ 'pagination': { 'page': page.page, 'total': page.pages, 'has_next': page.has_next, 'next_page': page.next_num }, 'devices': devices }) return make_response(result, 200) except HTTPRequestError as e: if isinstance(e.message, dict): return make_response(json.dumps(e.message), e.error_code) else: return format_response(e.error_code, e.message)
def get_devices(): """ Fetches known devices, potentially limited by a given value. Ordering might be user-configurable too. """ try: init_tenant_context(request, db) page_number, per_page = get_pagination(request) page = Device.query.paginate(page=page_number, per_page=per_page, error_out=False) devices = [] for d in page.items: devices.append(serialize_full_device(d)) result = json.dumps({ 'pagination': { 'page': page.page, 'total': page.pages, 'has_next': page.has_next, 'next_page': page.next_num }, 'devices': devices }) return make_response(result, 200) except HTTPRequestError as e: if isinstance(e.message, dict): return make_response(json.dumps(e.message), e.error_code) else: return format_response(e.error_code, e.message)
def get_device(deviceid): try: init_tenant_context(request, db) orm_device = assert_device_exists(deviceid) return make_response(json.dumps(serialize_full_device(orm_device)), 200) except HTTPRequestError as e: if isinstance(e.message, dict): return make_response(json.dumps(e.message), e.error_code) else: return format_response(e.error_code, e.message)
def get_template(templateid): try: init_tenant_context(request, db) tpl = assert_template_exists(templateid) json_template = template_schema.dump(tpl).data return make_response(json.dumps(json_template), 200) except HTTPRequestError as e: if isinstance(e.message, dict): return make_response(json.dumps(e.message), e.error_code) else: return format_response(e.error_code, e.message)
def remove_device(deviceid): try: init_tenant_context(request, db) orm_device = assert_device_exists(deviceid) data = serialize_full_device(orm_device) db.session.delete(orm_device) db.session.commit() results = json.dumps({'result': 'ok', 'removed_device': data}) return make_response(results, 200) except HTTPRequestError as e: if isinstance(e.message, dict): return make_response(json.dumps(e.message), e.error_code) else: return format_response(e.error_code, e.message)
def remove_template(templateid): try: init_tenant_context(request, db) tpl = assert_template_exists(templateid) json_template = template_schema.dump(tpl).data db.session.delete(tpl) db.session.commit() results = json.dumps({'result': 'ok', 'removed': json_template}) return make_response(results, 200) except HTTPRequestError as e: if isinstance(e.message, dict): return make_response(json.dumps(e.message), e.error_code) else: return format_response(e.error_code, e.message)
def add_template_to_device(deviceid, templateid): """ associates given template with device """ try: tenant = init_tenant_context(request, db) orm_device = assert_device_exists(deviceid) orm_template = assert_template_exists(templateid) orm_device.templates.append(orm_template) try: db.session.commit() except IntegrityError as error: handle_consistency_exception(error) result = { 'message': 'device updated', 'device': serialize_full_device(orm_device) } return make_response(json.dumps(result)) except HTTPRequestError as e: if isinstance(e.message, dict): return make_response(json.dumps(e.message), e.error_code) else: return format_response(e.error_code, e.message)
def configure_device(deviceid): try: tenant = init_tenant_context(request, db) # In fact, the actual device is not needed. We must be sure that it exists. assert_device_exists(deviceid) json_payload = json.loads(request.data) kafka_handler = KafkaHandler() # Remove topic metadata from JSON to be sent to the device # Should this be moved to a HTTP header? topic = json_payload["topic"] del json_payload["topic"] kafka_handler.configure(json_payload, meta={ "service": tenant, "id": deviceid, "topic": topic }) result = {'message': 'configuration sent'} return make_response(result, 200) except HTTPRequestError as e: if isinstance(e.message, dict): return make_response(json.dumps(e.message), e.error_code) else: return format_response(e.error_code, e.message)
def update_device(deviceid): try: tenant = init_tenant_context(request, db) old_device = assert_device_exists(deviceid) device_data, json_payload = parse_payload(request, device_schema) device_data.pop('templates') updated_device = Device(**device_data) parse_template_list(json_payload['templates'], updated_device) updated_device.id = deviceid # update sanity check if 'attrs' in json_payload: error = "Attributes cannot be updated inline. Update the associated template instead." return format_response(400, error) # TODO revisit iotagent notification mechanism # protocolHandler = IotaHandler(service=tenant) # device_type = 'virtual' # old_type = old_device.protocol # new_type = updated_device.protocol # if (old_type != 'virtual') and (new_type != 'virtual'): # device_type = 'device' # protocolHandler.update(updated_device) # if old_type != new_type: # if old_type == 'virtual': # device_type = 'device' # protocolHandler.create(updated_device) # elif new_type == 'virtual': # protocolHandler.remove(updated_device.id) # TODO revisit device data persistence # subsHandler = PersistenceHandler(service=tenant) # subsHandler.remove(old_device.persistence) # updated_device.persistence = subsHandler.create(deviceid, device_type) # TODO remove this in favor of kafka as data broker.... ctx_broker_handler = OrionHandler(service=tenant) ctx_broker_handler.update(serialize_full_device(old_device)) db.session.delete(old_device) db.session.add(updated_device) try: db.session.commit() except IntegrityError as error: handle_consistency_exception(error) result = { 'message': 'device updated', 'device': serialize_full_device(updated_device) } return make_response(json.dumps(result)) except HTTPRequestError as e: if isinstance(e.message, dict): return make_response(json.dumps(e.message), e.error_code) else: return format_response(e.error_code, e.message)
def remove_template(templateid): try: init_tenant_context(request, db) tpl = assert_template_exists(templateid) json_template = template_schema.dump(tpl).data try: db.session.delete(tpl) db.session.commit() except IntegrityError: raise HTTPRequestError( 400, "Template cannot be removed as it is being used by devices") results = json.dumps({'result': 'ok', 'removed': json_template}) return make_response(results, 200) except HTTPRequestError as e: if isinstance(e.message, dict): return make_response(json.dumps(e.message), e.error_code) else: return format_response(e.error_code, e.message)
def create_device(): """ Creates and configures the given device (in json) """ try: tenant = init_tenant_context(request, db) device_data, json_payload = parse_payload(request, device_schema) device_data['id'] = generate_device_id() device_data.pop( 'templates') # handled separatly by parse_template_list orm_device = Device(**device_data) parse_template_list(json_payload['templates'], orm_device) auto_create_template(json_payload, orm_device) # TODO revisit iotagent notification procedure # protocol_handler = IotaHandler(service=tenant) # device_type = "virtual" # if orm_device.protocol != "virtual": # device_type = "device" # protocol_handler.create(orm_device) # TODO revisit history management # subscription_handler = PersistenceHandler(service=tenant) # orm_device.persistence = subscription_handler.create(orm_device.device_id, "device") db.session.add(orm_device) try: db.session.commit() except IntegrityError as error: handle_consistency_exception(error) full_device = serialize_full_device(orm_device) result = json.dumps({ 'message': 'device created', 'device': full_device }) # TODO remove this in favor of kafka as data broker.... ctx_broker_handler = OrionHandler(service=tenant) ctx_broker_handler.create(full_device) kafka_handler = KafkaHandler() kafka_handler.create(full_device, meta={"service": tenant}) return make_response(result, 200) except HTTPRequestError as e: if isinstance(e.message, dict): return make_response(json.dumps(e.message), e.error_code) else: return format_response(e.error_code, e.message)
def remove_template_from_device(deviceid, templateid): """ removes given template from device """ try: tenant = init_tenant_context(request, db) device = assert_device_exists(deviceid) relation = assert_device_relation_exists(deviceid, templateid) # Here (for now) there are no more validations to perform, as template removal # cannot violate attribute constraints db.session.remove(relation) db.session.commit() result = {'message': 'device updated', 'device': serialize_full_device(device)} return make_response(json.dumps(result)) except HTTPRequestError as e: if isinstance(e.message, dict): return make_response(json.dumps(e.message), e.error_code) else: return format_response(e.error_code, e.message)
def create_device(): """ Creates and configures the given device (in json) """ try: tenant = init_tenant_context(request, db) try: count = int(request.args.get('count', '1')) clength = len(str(count)) verbose = request.args.get('verbose', 'false') in ['true', '1', 'True'] if verbose and count != 1: raise HTTPRequestError(400, "Verbose can only be used for single device creation") except ValueError as e: LOGGER.error(e) raise HTTPRequestError(400, "If provided, count must be integer") def indexed_label(base, index): if count == 1: return base else: return "{}_{:0{width}d}".format(base, index, width=clength) devices = [] # Handlers ctx_broker_handler = OrionHandler(service=tenant) kafka_handler = KafkaHandler() subs_handler = PersistenceHandler(service=tenant) for i in range(0, count): device_data, json_payload = parse_payload(request, device_schema) device_data['id'] = generate_device_id() device_data['label'] = indexed_label(device_data['label'], i) device_data.pop('templates', None) # handled separately by parse_template_list orm_device = Device(**device_data) parse_template_list(json_payload.get('templates', []), orm_device) auto_create_template(json_payload, orm_device) db.session.add(orm_device) devices.append({'id': device_data['id'], 'label': device_data['label']}) full_device = serialize_full_device(orm_device) # TODO remove this in favor of kafka as data broker.... # Updating handlers ctx_broker_handler.create(full_device) kafka_handler.create(full_device, meta={"service": tenant}) # Generating 'device type' field for history type_descr = "template" for dev_type in full_device['attrs'].keys(): type_descr += "_" + str(dev_type) subid = subs_handler.create(full_device['id'], type_descr) orm_device.persistence = subid try: db.session.commit() except IntegrityError as error: handle_consistency_exception(error) if verbose: result = json.dumps({ 'message': 'device created', 'device': full_device }) else: result = json.dumps({ 'message': 'devices created', 'devices': devices }) # TODO revisit iotagent notification procedure # protocol_handler = IotaHandler(service=tenant) # device_type = "virtual" # if orm_device.protocol != "virtual": # device_type = "device" # protocol_handler.create(orm_device) return make_response(result, 200) except HTTPRequestError as e: if isinstance(e.message, dict): return make_response(json.dumps(e.message), e.error_code) else: return format_response(e.error_code, e.message)