From 0bd8a7d9dee951598fa03ba4726fc740b7635ccb Mon Sep 17 00:00:00 2001 From: Li Liu Date: Wed, 17 Oct 2018 23:30:44 -0400 Subject: [PATCH] Added downloading bitstream when programming fpga How to test the flow of program process manually: 1. generate the fake env by the follow command cat > ./fake_env.sh << EOL SYSINFO=cyborg/accelerator/drivers/fpga/intel/sysinfo.py UTILS=cyborg/accelerator/drivers/fpga/utils.py sed -i -e 's/^\(SYS_FPGA\) = "\(\/sys\/class\/fpga\)"$/\1 = "\/tmp\2"/g' $SYSINFO sed -i -e 's/^\(SYS_FPGA_PATH\) = "\(\/sys\/class\/fpga\)"$/\1 = "\/tmp\2"/g' $UTILS python cyborg/tests/unit/accelerator/drivers/fpga/intel/prepare_test_data.py LOG=/tmp/intel_fpga_program.log sudo echo 'echo fpgaconf \$@ '"|tee $LOG" > /usr/bin/fpgaconf sudo echo "date |tee -a $LOG" >> /usr/bin/fpgaconf sudo echo "echo 'Program intel FPGA successfully' |tee -a $LOG" >> /usr/bin/fpgaconf sudo chmod a+x /usr/bin/fpgaconf EOL chmod a+x ./fake_env.sh sudo ./fake_env.sh 2. Please use curl command as follows: curl -s -X PATCH -H "X-Auth-Token: $OS_TOKEN" -H "Content-Type: application/json"\ -d '[{ "path": "/program", "op": "replace", "value": [{ "image_uuid": "{image_uuid}" }] }]'\ http://{host_ip}:6666/v1/accelerators/deployables/{deployable_uuid}/program 3. Checke the /tmp/intel_fpga_program.log it should see the infomation as the follow exmaple: $ cat /tmp/intel_fpga_program.log fpgaconf -b 04 -d 00 -f 1 4047d422-5d2f-432c-b87f-5e1749e95ee6.bin Sat Oct 27 15:08:34 UTC 2018 Program intel FPGA successfully Change-Id: I70ff5edac65fe9e9ec1783d62c2ecd21ac5fab18 --- .../accelerator/drivers/fpga/intel/driver.py | 2 +- cyborg/agent/manager.py | 24 +++++++++++++++++-- cyborg/agent/rpcapi.py | 19 ++++++++++++++- cyborg/api/controllers/v1/__init__.py | 2 ++ cyborg/api/controllers/v1/deployables.py | 5 ++++ .../unit/accelerator/drivers/fpga/base.py | 2 +- .../accelerator/drivers/fpga/intel/driver.py | 2 +- .../api/controllers/v1/test_fpga_program.py | 5 +++- 8 files changed, 54 insertions(+), 7 deletions(-) diff --git a/cyborg/accelerator/drivers/fpga/intel/driver.py b/cyborg/accelerator/drivers/fpga/intel/driver.py index b1e24625..7d0c7741 100644 --- a/cyborg/accelerator/drivers/fpga/intel/driver.py +++ b/cyborg/accelerator/drivers/fpga/intel/driver.py @@ -46,7 +46,7 @@ class IntelFPGADriver(FPGADriver): else: bdf = sysinfo.get_bdf_by_path(path) bdfs = sysinfo.split_bdf(bdf) - cmd = ["sudo", "fpgaconf"] + cmd = ["sudo", "/usr/bin/fpgaconf"] for i in zip(["-b", "-d", "-f"], bdfs): cmd.extend(i) cmd.append(image) diff --git a/cyborg/agent/manager.py b/cyborg/agent/manager.py index c1cdf486..5773ec72 100644 --- a/cyborg/agent/manager.py +++ b/cyborg/agent/manager.py @@ -18,6 +18,8 @@ from oslo_service import periodic_task from cyborg.accelerator.drivers.fpga.base import FPGADriver from cyborg.agent.resource_tracker import ResourceTracker +from cyborg.agent.rpcapi import AgentAPI +from cyborg.image.api import API as ImageAPI from cyborg.conductor import rpcapi as cond_api from cyborg.conf import CONF @@ -34,6 +36,8 @@ class AgentManager(periodic_task.PeriodicTasks): self.host = host or CONF.host self.fpga_driver = FPGADriver() self.cond_api = cond_api.ConductorAPI() + self.agent_api = AgentAPI() + self.image_api = ImageAPI() self._rt = ResourceTracker(host, self.cond_api) def periodic_tasks(self, context, raise_on_error=False): @@ -43,11 +47,27 @@ class AgentManager(periodic_task.PeriodicTasks): """List installed hardware.""" pass - def fpga_program(self, context, accelerator, image): + def fpga_program(self, context, deployable_uuid, image_uuid): """ Program a FPGA regoin, image can be a url or local file""" # TODO (Shaohe Feng) Get image from glance. # And add claim and rollback logical. - raise NotImplementedError() + path = self._download_bitstream(context, image_uuid) + dep = self.cond_api.deployable_get(context, deployable_uuid) + driver = self.fpga_driver.create(dep.vendor) + driver.program(dep.address, path) + + def _download_bitstream(self, context, bitstream_uuid): + """download the bistream + + :param context: the context + :param bistream_uuid: v4 uuid of the bitstream to reprogram + :returns: the path to bitstream downloaded, None if fail to download + """ + download_path = "/tmp/" + bitstream_uuid + ".bin" + self.image_api.download(context, + bitstream_uuid, + dest_path=download_path) + return download_path @periodic_task.periodic_task(run_immediately=True) def update_available_resource(self, context, startup=True): diff --git a/cyborg/agent/rpcapi.py b/cyborg/agent/rpcapi.py index f683dc01..2b9cd38b 100644 --- a/cyborg/agent/rpcapi.py +++ b/cyborg/agent/rpcapi.py @@ -21,7 +21,7 @@ import oslo_messaging as messaging from cyborg.common import constants from cyborg.common import rpc from cyborg.objects import base as objects_base - +from cyborg import objects CONF = cfg.CONF @@ -50,3 +50,20 @@ class AgentAPI(object): def hardware_list(self, context, values): """Signal the agent to find local hardware.""" pass + + def program_fpga_with_bitstream(self, + context, + deployable_uuid, + bitstream_uuid): + """Actiion to program a target FPGA""" + version = '1.0' + + dpl_get = objects.Deployable.get(context, deployable_uuid) + if not dpl_get: + # TODO (Li Liu) throw an exception here + return 0 + + cctxt = self.client.prepare(server=dpl_get.host, version=version) + return cctxt.call(context, 'fpga_program', + deployable_uuid=deployable_uuid, + image_uuid=bitstream_uuid) diff --git a/cyborg/api/controllers/v1/__init__.py b/cyborg/api/controllers/v1/__init__.py index 6b3d2085..20b13d72 100644 --- a/cyborg/api/controllers/v1/__init__.py +++ b/cyborg/api/controllers/v1/__init__.py @@ -22,6 +22,7 @@ from wsme import types as wtypes from cyborg.api.controllers import base from cyborg.api.controllers import link from cyborg.api.controllers.v1 import accelerators +from cyborg.api.controllers.v1 import deployables from cyborg.api import expose @@ -51,6 +52,7 @@ class Controller(rest.RestController): """Version 1 API controller root""" accelerators = accelerators.AcceleratorsController() + deployables = deployables.DeployablesController() @expose.expose(V1) def get(self): diff --git a/cyborg/api/controllers/v1/deployables.py b/cyborg/api/controllers/v1/deployables.py index c7c2ca69..94210ea5 100644 --- a/cyborg/api/controllers/v1/deployables.py +++ b/cyborg/api/controllers/v1/deployables.py @@ -28,6 +28,7 @@ from cyborg.common import exception from cyborg.common import policy from cyborg import objects from cyborg.quota import QUOTAS +from cyborg.agent.rpcapi import AgentAPI class Deployable(base.APIBase): @@ -151,10 +152,14 @@ class DeployablesController(base.CyborgController): """ image_uuid = program_info[0]['value'][0]['image_uuid'] + agent_api = AgentAPI() obj_dep = objects.Deployable.get(pecan.request.context, uuid) # Set attribute of the new bitstream/image information obj_dep.add_attribute(pecan.request.context, 'image_uuid', image_uuid) # TODO (Li Liu) Trigger the program api in Agnet. + agent_api.program_fpga_with_bitstream(pecan.request.context, + uuid, + image_uuid) return Deployable.convert_with_links(obj_dep) @policy.authorize_wsgi("cyborg:deployable", "create", False) diff --git a/cyborg/tests/unit/accelerator/drivers/fpga/base.py b/cyborg/tests/unit/accelerator/drivers/fpga/base.py index 20413300..0bd6ab69 100644 --- a/cyborg/tests/unit/accelerator/drivers/fpga/base.py +++ b/cyborg/tests/unit/accelerator/drivers/fpga/base.py @@ -92,7 +92,7 @@ class TestFPGADriver(base.TestCase): b = "0x5e" d = "0x00" f = "0x0" - expect_cmd = ['sudo', 'fpgaconf', '-b', b, + expect_cmd = ['sudo', '/usr/bin/fpgaconf', '-b', b, '-d', d, '-f', f, '/path/image'] mock_popen.return_value = p() intel = FPGADriver.create("intel") diff --git a/cyborg/tests/unit/accelerator/drivers/fpga/intel/driver.py b/cyborg/tests/unit/accelerator/drivers/fpga/intel/driver.py index 5760ecf7..6719d7ca 100644 --- a/cyborg/tests/unit/accelerator/drivers/fpga/intel/driver.py +++ b/cyborg/tests/unit/accelerator/drivers/fpga/intel/driver.py @@ -80,7 +80,7 @@ class TestIntelFPGADriver(base.TestCase): b = "0x5e" d = "0x00" f = "0x0" - expect_cmd = ['sudo', 'fpgaconf', '-b', b, + expect_cmd = ['sudo', '/usr/bin/fpgaconf', '-b', b, '-d', d, '-f', f, '/path/image'] mock_popen.return_value = p() intel = IntelFPGADriver() diff --git a/cyborg/tests/unit/api/controllers/v1/test_fpga_program.py b/cyborg/tests/unit/api/controllers/v1/test_fpga_program.py index 2e0db881..43734f31 100644 --- a/cyborg/tests/unit/api/controllers/v1/test_fpga_program.py +++ b/cyborg/tests/unit/api/controllers/v1/test_fpga_program.py @@ -19,6 +19,7 @@ from six.moves import http_client from cyborg.api.controllers.v1.deployables import Deployable from cyborg.tests.unit.api.controllers.v1 import base as v1_test from cyborg.tests.unit import fake_deployable +from cyborg.agent.rpcapi import AgentAPI class TestFPGAProgramController(v1_test.APITestV1): @@ -29,13 +30,15 @@ class TestFPGAProgramController(v1_test.APITestV1): self.deployable_uuids = ['0acbf8d6-e02a-4394-aae3-57557d209498'] @mock.patch('cyborg.objects.Deployable.get') - def test_program(self, mock_get_dep): + @mock.patch('cyborg.agent.rpcapi.AgentAPI.program_fpga_with_bitstream') + def test_program(self, mock_program, mock_get_dep): self.headers['X-Roles'] = 'admin' self.headers['Content-Type'] = 'application/json' dep_uuid = self.deployable_uuids[0] fake_dep = fake_deployable.fake_deployable_obj(self.context, uuid=dep_uuid) mock_get_dep.return_value = fake_dep + mock_program.return_value = None body = [{"image_uuid": "9a17439a-85d0-4c53-a3d3-0f68a2eac896"}] response = self.\ patch_json('/accelerators/deployables/%s/program' % dep_uuid,