Skip to content

Commit

Permalink
Merge pull request #66 from mmagr/attribute_labels
Browse files Browse the repository at this point in the history
Implements attribute label restrictions
  • Loading branch information
mmagr committed Apr 12, 2018
2 parents 576e78f + b5e3106 commit 18cbb26
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 99 deletions.
76 changes: 30 additions & 46 deletions DeviceManager/DeviceHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,24 @@

import logging
import re
import json
from datetime import datetime
from flask import request
from flask import Blueprint
from flask import request, jsonify, Blueprint, make_response
from sqlalchemy.exc import IntegrityError

from DeviceManager.utils import *
# from DeviceManager.utils import *
from DeviceManager.utils import create_id, get_pagination, format_response
from DeviceManager.utils import HTTPRequestError
from DeviceManager.conf import CONFIG
from DeviceManager.BackendHandler import OrionHandler, KafkaHandler, PersistenceHandler

from DeviceManager.DatabaseModels import db, assert_device_exists, assert_template_exists
from DeviceManager.DatabaseModels import handle_consistency_exception, assert_device_relation_exists
from DeviceManager.DatabaseModels import DeviceTemplate, DeviceAttr, Device, DeviceTemplateMap
from DeviceManager.DatabaseModels import DeviceOverride
from DeviceManager.SerializationModels import *
from DeviceManager.SerializationModels import device_list_schema, device_schema
from DeviceManager.SerializationModels import attr_list_schema
from DeviceManager.SerializationModels import parse_payload, load_attrs
from DeviceManager.TenancyManager import init_tenant_context
from DeviceManager.app import app
from .StatusMonitor import StatusMonitor
Expand All @@ -30,13 +34,13 @@
LOGGER.setLevel(logging.INFO)

def serialize_full_device(orm_device, tenant):
data = device_schema.dump(orm_device).data
data = device_schema.dump(orm_device)
status = StatusMonitor.get_status(tenant, orm_device.id)
if status is not None:
data['status'] = status
data['attrs'] = {}
for template in orm_device.templates:
data['attrs'][template.id] = attr_list_schema.dump(template.attrs).data
data['attrs'][template.id] = attr_list_schema.dump(template.attrs)

for override in orm_device.overrides:
for attr in data['attrs'][override.attr.template_id]:
Expand All @@ -63,7 +67,7 @@ def auto_create_template(json_payload, new_device):
for attr in json_payload['attrs']:
orm_template = find_template(new_device.templates, attr['template_id'])
if orm_template is None:
raise HTTPRequestError(400, 'Unknown template "{}" in attr list'.format(template))
raise HTTPRequestError(400, 'Unknown template "{}" in attr list'.format(orm_template))

target = int(attr['id'])
found = False
Expand Down Expand Up @@ -454,12 +458,12 @@ def configure_device(req, device_id):
LOGGER.info('Configuration sent.')
result = {'status': 'configuration sent to device'}
else:
LOGGER.info('invalid attributes detected in command: {}'.format(invalid_attrs))
result = {
'status': 'some of the attributes are not configurable',
'attrs': invalid_attrs
}

LOGGER.info('Configuration sent.')
return result

@staticmethod
Expand Down Expand Up @@ -579,14 +583,10 @@ def flask_get_devices():
"""
try:
result = DeviceHandler.get_devices(request)
resp = make_response(json.dumps(result), 200)
resp.mimetype = "application/json"
return resp
return make_response(jsonify(result), 200)
except HTTPRequestError as e:
if isinstance(e.message, dict):
resp = make_response(json.dumps(e.message), e.error_code)
resp.mimetype = "application/json"
return resp
return make_response(jsonify(e.message), e.error_code)
else:
return format_response(e.error_code, e.message)

Expand All @@ -601,12 +601,10 @@ def flask_create_device():
"""
try:
result = DeviceHandler.create_device(request)
resp = make_response(json.dumps(result), 200)
resp.mimetype = "application/json"
return resp
return make_response(jsonify(result), 200)
except HTTPRequestError as e:
if isinstance(e.message, dict):
return make_response(json.dumps(e.message), e.error_code)
return make_response(jsonify(e.message), e.error_code)
else:
return format_response(e.error_code, e.message)

Expand All @@ -615,12 +613,10 @@ def flask_create_device():
def flask_get_device(device_id):
try:
result = DeviceHandler.get_device(request, device_id)
resp = make_response(json.dumps(result), 200)
resp.mimetype = "application/json"
return resp
return make_response(jsonify(result), 200)
except HTTPRequestError as e:
if isinstance(e.message, dict):
return make_response(json.dumps(e.message), e.error_code)
return make_response(jsonify(e.message), e.error_code)
else:
return format_response(e.error_code, e.message)

Expand All @@ -629,12 +625,10 @@ def flask_get_device(device_id):
def flask_remove_device(device_id):
try:
results = DeviceHandler.delete_device(request, device_id)
resp = make_response(json.dumps(results), 200)
resp.mimetype = "application/json"
return resp
return make_response(jsonify(results), 200)
except HTTPRequestError as e:
if isinstance(e.message, dict):
return make_response(json.dumps(e.message), e.error_code)
return make_response(jsonify(e.message), e.error_code)
else:
return format_response(e.error_code, e.message)

Expand All @@ -643,12 +637,10 @@ def flask_remove_device(device_id):
def flask_update_device(device_id):
try:
results = DeviceHandler.update_device(request, device_id)
resp = make_response(json.dumps(results), 200)
resp.mimetype = "application/json"
return resp
return make_response(jsonify(results), 200)
except HTTPRequestError as e:
if isinstance(e.message, dict):
return make_response(json.dumps(e.message), e.error_code)
return make_response(jsonify(e.message), e.error_code)
else:
return format_response(e.error_code, e.message)

Expand All @@ -660,13 +652,11 @@ def flask_configure_device(device_id):
"""
try:
result = DeviceHandler.configure_device(request, device_id)
resp = make_response(json.dumps(result), 200)
resp.mimetype = "application/json"
return resp
return make_response(jsonify(result), 200)

except HTTPRequestError as error:
if isinstance(error.message, dict):
return make_response(json.dumps(error.message), error.error_code)
return make_response(jsonify(error.message), error.error_code)
else:
return format_response(error.error_code, error.message)

Expand All @@ -677,12 +667,10 @@ def flask_add_template_to_device(device_id, template_id):
try:
result = DeviceHandler.add_template_to_device(
request, device_id, template_id)
resp = make_response(json.dumps(result), 200)
resp.mimetype = "application/json"
return resp
return make_response(jsonify(result), 200)
except HTTPRequestError as e:
if isinstance(e.message, dict):
return make_response(json.dumps(e.message), e.error_code)
return make_response(jsonify(e.message), e.error_code)
else:
return format_response(e.error_code, e.message)

Expand All @@ -692,12 +680,10 @@ def flask_remove_template_from_device(device_id, template_id):
try:
result = DeviceHandler.remove_template_from_device(
request, device_id, template_id)
resp = make_response(json.dumps(result), 200)
resp.mimetype = "application/json"
return resp
return make_response(jsonify(result), 200)
except HTTPRequestError as e:
if isinstance(e.message, dict):
return make_response(json.dumps(e.message), e.error_code)
return make_response(jsonify(e.message), e.error_code)
else:
return format_response(e.error_code, e.message)

Expand All @@ -706,12 +692,10 @@ def flask_remove_template_from_device(device_id, template_id):
def flask_get_by_template(template_id):
try:
result = DeviceHandler.get_by_template(request, template_id)
resp = make_response(json.dumps(result), 200)
resp.mimetype = "application/json"
return resp
return make_response(jsonify(result), 200)
except HTTPRequestError as e:
if isinstance(e.message, dict):
return make_response(json.dumps(e.message), e.error_code)
return make_response(jsonify(e.message), e.error_code)
else:
return format_response(e.error_code, e.message)

Expand Down
4 changes: 2 additions & 2 deletions DeviceManager/KafkaNotifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

LOGGER = logging.getLogger('device-manager.' + __name__)
LOGGER.addHandler(logging.StreamHandler())
LOGGER.setLevel(logging.DEBUG)
LOGGER.setLevel(logging.WARNING)


class DeviceEvent:
Expand Down Expand Up @@ -73,7 +73,7 @@ def send_notification(event, device, meta):
full_msg = NotificationMessage(event, device, meta)
try:
topic = get_topic(meta['service'], CONFIG.subject)
LOGGER.info("topic for '{}' is '{}'".format(CONFIG.subject, topic))
LOGGER.debug("topic for '{}' is '{}'".format(CONFIG.subject, topic))
if topic is None:
LOGGER.error("Failed to retrieve named topic to publish to")

Expand Down
17 changes: 12 additions & 5 deletions DeviceManager/SerializationModels.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# object to json sweetness
import json
import re
from marshmallow import Schema, fields, post_dump, ValidationError

from DeviceManager.utils import HTTPRequestError
Expand All @@ -14,9 +15,15 @@ class MetaSchema(Schema):
value_type = fields.Str(required=True)
static_value = fields.Field()

def validate_attr_label(input):
if re.match(r'^[a-zA-Z0-9_-]+$', input) is None:
print('validation for {} failed'.format(input))
raise ValidationError("Labels must contain letters, numbers or dashes(-_)")
return '-- invalid --'

class AttrSchema(Schema):
id = fields.Int()
label = fields.Str(required=True)
label = fields.Str(required=True, validate=validate_attr_label, allow_none=False, missing=None)
created = fields.DateTime(dump_only=True)
updated = fields.DateTime(dump_only=True)
type = fields.Str(required=True)
Expand Down Expand Up @@ -75,11 +82,11 @@ def parse_payload(request, schema):
if (content_type is None) or (content_type != "application/json"):
raise HTTPRequestError(400, "Payload must be valid JSON, and Content-Type set accordingly")
json_payload = json.loads(request.data)
data = schema.load(json_payload).data
data = schema.load(json_payload)
except ValueError:
raise HTTPRequestError(400, "Payload must be valid JSON, and Content-Type set accordingly")
except ValidationError as errors:
results = {'message': 'failed to parse input', 'errors': errors}
results = {'message': 'failed to parse input', 'errors': errors.messages}
raise HTTPRequestError(400, results)
return data, json_payload

Expand All @@ -90,7 +97,7 @@ def load_attrs(attr_list, parent_template, base_type, db):
"""
for attr in attr_list:
try:
entity = attr_schema.load(attr).data
entity = attr_schema.load(attr)
try:
children = entity.pop('children')
except KeyError:
Expand All @@ -103,5 +110,5 @@ def load_attrs(attr_list, parent_template, base_type, db):
orm_child = DeviceAttr(parent=orm_entity, **child)
db.session.add(orm_child)
except ValidationError as errors:
results = {'message': 'failed to parse attr', 'errors': errors}
results = {'message': 'failed to parse attr', 'errors': errors.messages}
raise HTTPRequestError(400, results)

0 comments on commit 18cbb26

Please sign in to comment.