| # Copyright 2014 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Module contains a simple implementation of the devices RPC.""" |
| |
| from cherrypy import tools |
| |
| import common |
| from cros_lib.fake_device_server import common_util |
| from cros_lib.fake_device_server import resource_method |
| from cros_lib.fake_device_server import server_errors |
| |
| |
| # TODO(sosa): All access to this object should technically require auth. Create |
| # setters/getters for the auth token for testing. |
| |
| |
| class Devices(resource_method.ResourceMethod): |
| """A simple implementation of the device interface. |
| |
| A common workflow of using this API is: |
| |
| POST .../ # Creates a new device with id <id>. |
| PATCH ..../<id> # Update device state. |
| GET .../<id> # Get device state. |
| DELETE .../<id> # Delete the device. |
| """ |
| |
| # Needed for cherrypy to expose this to requests. |
| exposed = True |
| |
| # Requires keys in device_config to create a device. |
| required_keys = ['systemName', 'deviceKind', 'channel'] |
| |
| |
| |
| def __init__(self, resource, commands_instance): |
| """Initializes a registration ticket. |
| |
| @param resource: A resource delegate for storing devices. |
| @param commands_instance: Instance of commands method class. |
| """ |
| super(Devices, self).__init__(resource) |
| self.commands_instance = commands_instance |
| |
| |
| def create_device(self, api_key, device_config): |
| """Creates a new device given the device_config. |
| |
| @param api_key: Api key for the application. |
| @param device_config: Json dict for the device. |
| @raises server_errors.HTTPError: if the config is missing a required key |
| """ |
| # Verify required keys exist in the device draft. |
| for key in self.required_keys: |
| if key not in device_config: |
| raise server_errors.HTTPError(400, 'Must specify %s' % key) |
| |
| # Create default state. |
| device_config['kind'] = 'clouddevices#device' |
| device_config['state'] = { 'version': '', |
| 'base': { 'connectionStatus': 'online'}, |
| } |
| device_config['etag'] = '0' # SOMETHING RANDOM |
| device_config['owner'] = '0' # GET OWNER |
| |
| new_device = self.resource.update_data_val(None, api_key, |
| data_in=device_config) |
| self.commands_instance.new_device(new_device['id'], api_key) |
| return new_device |
| |
| |
| @tools.json_out() |
| def GET(self, *args, **kwargs): |
| """GET .../(device_id) gets device info or lists all devices. |
| |
| Supports both the GET / LIST commands for devices. List lists all |
| devices a user has access to, however, this implementation just returns |
| all devices. |
| |
| Raises: |
| server_errors.HTTPError if the device doesn't exist. |
| """ |
| id, api_key, _ = common_util.parse_common_args(args, kwargs) |
| if id: |
| return self.resource.get_data_val(id, api_key) |
| else: |
| # Returns listing (ignores optional parameters). |
| listing = {'kind': 'clouddevices#devicesListResponse'} |
| listing['devices'] = self.resource.get_data_vals() |
| return listing |
| |
| |
| @tools.json_out() |
| def POST(self, *args, **kwargs): |
| """Creates a new device using the incoming json data.""" |
| id, api_key, _ = common_util.parse_common_args(args, kwargs) |
| data = common_util.parse_serialized_json() |
| |
| if id: |
| raise server_errors.HTTPError(400, 'Cannot pass an id to INSERT') |
| if not data: |
| data = {} |
| |
| return self.create_device(api_key, data) |
| |
| |
| def DELETE(self, *args, **kwargs): |
| """Deletes the given device. |
| |
| Format of this call is: |
| DELETE .../device_id |
| |
| Raises: |
| server_errors.HTTPError if the device doesn't exist. |
| """ |
| id, api_key, _ = common_util.parse_common_args(args, kwargs) |
| self.resource.del_data_val(id, api_key) |
| self.commands_instance.remove_device(id, api_key) |