quantnet-agent 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- quantnet_agent-1.0.0/LICENSE +41 -0
- quantnet_agent-1.0.0/MANIFEST.in +7 -0
- quantnet_agent-1.0.0/PKG-INFO +83 -0
- quantnet_agent-1.0.0/README.md +57 -0
- quantnet_agent-1.0.0/config/logging.conf +34 -0
- quantnet_agent-1.0.0/pyproject.toml +35 -0
- quantnet_agent-1.0.0/quantnet_agent/__init__.py +1 -0
- quantnet_agent-1.0.0/quantnet_agent/cli.py +80 -0
- quantnet_agent-1.0.0/quantnet_agent/common/__init__.py +2 -0
- quantnet_agent-1.0.0/quantnet_agent/common/calibration_status.py +7 -0
- quantnet_agent-1.0.0/quantnet_agent/common/config.py +135 -0
- quantnet_agent-1.0.0/quantnet_agent/common/constants.py +28 -0
- quantnet_agent-1.0.0/quantnet_agent/common/logging.py +60 -0
- quantnet_agent-1.0.0/quantnet_agent/hal/HAL.py +231 -0
- quantnet_agent-1.0.0/quantnet_agent/hal/__init__.py +0 -0
- quantnet_agent-1.0.0/quantnet_agent/hal/driver/OZoptics.py +46 -0
- quantnet_agent-1.0.0/quantnet_agent/hal/driver/Thorlabs.py +39 -0
- quantnet_agent-1.0.0/quantnet_agent/hal/driver/__init__.py +0 -0
- quantnet_agent-1.0.0/quantnet_agent/hal/driver/artiq.py +124 -0
- quantnet_agent-1.0.0/quantnet_agent/hal/driver/dummy.py +373 -0
- quantnet_agent-1.0.0/quantnet_agent/hal/driver/overlayepc.py +27 -0
- quantnet_agent-1.0.0/quantnet_agent/hal/driver/overlayexpframework.py +47 -0
- quantnet_agent-1.0.0/quantnet_agent/hal/driver/overlaylightsrc.py +125 -0
- quantnet_agent-1.0.0/quantnet_agent/hal/driver/overlaymeter.py +58 -0
- quantnet_agent-1.0.0/quantnet_agent/hal/driver/simulator.py +345 -0
- quantnet_agent-1.0.0/quantnet_agent/hal/hwclasses.py +148 -0
- quantnet_agent-1.0.0/quantnet_agent/hal/interpreter/__init__.py +0 -0
- quantnet_agent-1.0.0/quantnet_agent/hal/interpreter/calibration.py +101 -0
- quantnet_agent-1.0.0/quantnet_agent/hal/interpreter/calibration_interpreter.py +43 -0
- quantnet_agent-1.0.0/quantnet_agent/hal/interpreter/dummy_cavity_calibration.py +16 -0
- quantnet_agent-1.0.0/quantnet_agent/hal/interpreter/dummy_lsrc_calibration.py +16 -0
- quantnet_agent-1.0.0/quantnet_agent/hal/interpreter/exp_framework.py +75 -0
- quantnet_agent-1.0.0/quantnet_agent/hal/interpreter/scheduler.py +35 -0
- quantnet_agent-1.0.0/quantnet_agent/hal/local_task_manager.py +249 -0
- quantnet_agent-1.0.0/quantnet_agent/hal/node.py +205 -0
- quantnet_agent-1.0.0/quantnet_agent/interpreter/test_interpreter.py +32 -0
- quantnet_agent-1.0.0/quantnet_agent/scheduler/__init__.py +0 -0
- quantnet_agent-1.0.0/quantnet_agent/scheduler/scheduler.py +483 -0
- quantnet_agent-1.0.0/quantnet_agent/service/__init__.py +1 -0
- quantnet_agent-1.0.0/quantnet_agent/service/agent.py +98 -0
- quantnet_agent-1.0.0/quantnet_agent/service/register.py +77 -0
- quantnet_agent-1.0.0/quantnet_agent.egg-info/PKG-INFO +83 -0
- quantnet_agent-1.0.0/quantnet_agent.egg-info/SOURCES.txt +47 -0
- quantnet_agent-1.0.0/quantnet_agent.egg-info/dependency_links.txt +1 -0
- quantnet_agent-1.0.0/quantnet_agent.egg-info/entry_points.txt +2 -0
- quantnet_agent-1.0.0/quantnet_agent.egg-info/requires.txt +12 -0
- quantnet_agent-1.0.0/quantnet_agent.egg-info/top_level.txt +1 -0
- quantnet_agent-1.0.0/requirements.txt +12 -0
- quantnet_agent-1.0.0/setup.cfg +4 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
QUANT-NET Control Plane Framework (QNCP) Copyright (c) 2025, The Regents of the
|
|
2
|
+
University of California, through Lawrence Berkeley National Laboratory (subject
|
|
3
|
+
to receipt of any required approvals from the U.S. Dept. of Energy). All rights
|
|
4
|
+
reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without modification,
|
|
7
|
+
are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
(1) Redistributions of source code must retain the above copyright notice, this
|
|
10
|
+
list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
(2) Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
this list of conditions and the following disclaimer in the documentation and/or
|
|
14
|
+
other materials provided with the distribution.
|
|
15
|
+
|
|
16
|
+
(3) Neither the name of the University of California, Lawrence Berkeley National
|
|
17
|
+
Laboratory, U.S. Dept. of Energy nor the names of its contributors may be used
|
|
18
|
+
to endorse or promote products derived from this software without specific prior
|
|
19
|
+
written permission.
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
23
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
24
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
25
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
26
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
27
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
28
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
29
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
30
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
31
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
32
|
+
|
|
33
|
+
You are under no obligation whatsoever to provide any bug fixes, patches, or
|
|
34
|
+
upgrades to the features, functionality or performance of the source code
|
|
35
|
+
("Enhancements") to anyone; however, if you choose to make your Enhancements
|
|
36
|
+
available either publicly, or directly to Lawrence Berkeley National Laboratory,
|
|
37
|
+
without imposing a separate written license agreement for such Enhancements,
|
|
38
|
+
then you hereby grant the following license: a non-exclusive, royalty-free
|
|
39
|
+
perpetual license to install, use, modify, prepare derivative works, incorporate
|
|
40
|
+
into other computer software, distribute, and sublicense such enhancements or
|
|
41
|
+
derivative works thereof, in binary and source code form.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: quantnet-agent
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: The QN Agent for Quant-Net Control Plane
|
|
5
|
+
Author-email: ESnet <quantum@es.net>
|
|
6
|
+
License-Expression: BSD-3-Clause-LBNL
|
|
7
|
+
Project-URL: Homepage, https://github.com/quant-net/quant-net-agent
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Requires-Python: >=3.10
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Requires-Dist: asyncio-mqtt==0.16.1
|
|
14
|
+
Requires-Dist: click==8.1.3
|
|
15
|
+
Requires-Dist: uvloop==0.21.0
|
|
16
|
+
Requires-Dist: ThorlabsPM100
|
|
17
|
+
Requires-Dist: numpy==1.26.2
|
|
18
|
+
Requires-Dist: pyserial==3.3
|
|
19
|
+
Requires-Dist: configobj==5.0.9
|
|
20
|
+
Requires-Dist: apscheduler==3.10.4
|
|
21
|
+
Requires-Dist: pydantic==2.7.3
|
|
22
|
+
Requires-Dist: pyyaml==6.0.1
|
|
23
|
+
Requires-Dist: networkx==3.4.2
|
|
24
|
+
Requires-Dist: quantnet-mq
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# Quant-Net Agent
|
|
29
|
+
|
|
30
|
+
The QUANT-NET Control Plane (QNCP) runs as a distributed system. This Agent
|
|
31
|
+
registers resources, interfaces with devices, and interprets protocol commands
|
|
32
|
+
from a Controller instance. The Agent package includes the concept of extensible
|
|
33
|
+
command interpreters, which define the behavior of the Agents when processing
|
|
34
|
+
protocol messages and interacting with the underlying hardware or simulation
|
|
35
|
+
devices.
|
|
36
|
+
|
|
37
|
+
The Agent includes a hardware abstraction layer (HAL) that defines a base set of
|
|
38
|
+
hardware classes for managing the interaction with quantum devices and external
|
|
39
|
+
experiment control frameworks.
|
|
40
|
+
|
|
41
|
+
## Development Install
|
|
42
|
+
|
|
43
|
+
Pull requirements and install package in edit mode.
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
pip3 install -e .
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The `quantnet_agent` script will be available in your local path, or check `~/.local/bin`
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
$ quantnet_agent --help
|
|
53
|
+
Usage: quantnet_agent [OPTIONS]
|
|
54
|
+
|
|
55
|
+
Options:
|
|
56
|
+
-c, --config TEXT Main configuration file [default:
|
|
57
|
+
./config/agent.cfg]
|
|
58
|
+
-n, --node-config TEXT Node configuration file [default: ~/.quant-
|
|
59
|
+
net/node.json]
|
|
60
|
+
-a, --agent_id TEXT Specify an agent identifier [default: ]
|
|
61
|
+
--mq-broker-host TEXT Message queue broker host
|
|
62
|
+
--mq-broker-port INTEGER Message queue broker port
|
|
63
|
+
-d, --debug Enable debug logging
|
|
64
|
+
--interpreter-path TEXT Location of additional command interpreters
|
|
65
|
+
--schema-path TEXT Specify a path containing additional schema files
|
|
66
|
+
--help Show this message and exit.
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Example usage
|
|
70
|
+
|
|
71
|
+
An MQTT broker should be available for the agent to connect to. A development docker-compose file that starts an Eclipse Mosquitto instance is available in `quant-net-docker:docker-compose-backend.yml`
|
|
72
|
+
|
|
73
|
+
Testing node config files exist in `quant-net-mq:quant-net-mq/schemas/examples`
|
|
74
|
+
|
|
75
|
+
Running the agent:
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
quantnet_agent --mq-broker-host <broker> -n <path_to>/quant-net-mq/quantnet_mq/schema/examples/conf_qnode.json
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
|
|
2
|
+
# Quant-Net Agent
|
|
3
|
+
|
|
4
|
+
The QUANT-NET Control Plane (QNCP) runs as a distributed system. This Agent
|
|
5
|
+
registers resources, interfaces with devices, and interprets protocol commands
|
|
6
|
+
from a Controller instance. The Agent package includes the concept of extensible
|
|
7
|
+
command interpreters, which define the behavior of the Agents when processing
|
|
8
|
+
protocol messages and interacting with the underlying hardware or simulation
|
|
9
|
+
devices.
|
|
10
|
+
|
|
11
|
+
The Agent includes a hardware abstraction layer (HAL) that defines a base set of
|
|
12
|
+
hardware classes for managing the interaction with quantum devices and external
|
|
13
|
+
experiment control frameworks.
|
|
14
|
+
|
|
15
|
+
## Development Install
|
|
16
|
+
|
|
17
|
+
Pull requirements and install package in edit mode.
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
pip3 install -e .
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The `quantnet_agent` script will be available in your local path, or check `~/.local/bin`
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
$ quantnet_agent --help
|
|
27
|
+
Usage: quantnet_agent [OPTIONS]
|
|
28
|
+
|
|
29
|
+
Options:
|
|
30
|
+
-c, --config TEXT Main configuration file [default:
|
|
31
|
+
./config/agent.cfg]
|
|
32
|
+
-n, --node-config TEXT Node configuration file [default: ~/.quant-
|
|
33
|
+
net/node.json]
|
|
34
|
+
-a, --agent_id TEXT Specify an agent identifier [default: ]
|
|
35
|
+
--mq-broker-host TEXT Message queue broker host
|
|
36
|
+
--mq-broker-port INTEGER Message queue broker port
|
|
37
|
+
-d, --debug Enable debug logging
|
|
38
|
+
--interpreter-path TEXT Location of additional command interpreters
|
|
39
|
+
--schema-path TEXT Specify a path containing additional schema files
|
|
40
|
+
--help Show this message and exit.
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Example usage
|
|
44
|
+
|
|
45
|
+
An MQTT broker should be available for the agent to connect to. A development docker-compose file that starts an Eclipse Mosquitto instance is available in `quant-net-docker:docker-compose-backend.yml`
|
|
46
|
+
|
|
47
|
+
Testing node config files exist in `quant-net-mq:quant-net-mq/schemas/examples`
|
|
48
|
+
|
|
49
|
+
Running the agent:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
quantnet_agent --mq-broker-host <broker> -n <path_to>/quant-net-mq/quantnet_mq/schema/examples/conf_qnode.json
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[loggers]
|
|
2
|
+
keys=root,quantnet_agent,gmqtt
|
|
3
|
+
|
|
4
|
+
[handlers]
|
|
5
|
+
keys=console
|
|
6
|
+
|
|
7
|
+
[formatters]
|
|
8
|
+
keys=simple
|
|
9
|
+
|
|
10
|
+
[logger_root]
|
|
11
|
+
level=INFO
|
|
12
|
+
handlers=console
|
|
13
|
+
|
|
14
|
+
[logger_quantnet_agent]
|
|
15
|
+
level=DEBUG
|
|
16
|
+
handlers=console
|
|
17
|
+
qualname=agent
|
|
18
|
+
propagate=0
|
|
19
|
+
|
|
20
|
+
[logger_gmqtt]
|
|
21
|
+
level=CRITICAL
|
|
22
|
+
handlers=console
|
|
23
|
+
qualname=gmqtt
|
|
24
|
+
propagate=0
|
|
25
|
+
|
|
26
|
+
[handler_console]
|
|
27
|
+
class=StreamHandler
|
|
28
|
+
level=DEBUG
|
|
29
|
+
formatter=simple
|
|
30
|
+
args=(sys.stdout,)
|
|
31
|
+
|
|
32
|
+
[formatter_simple]
|
|
33
|
+
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
|
|
34
|
+
datefmt=
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools >= 77.0.3"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "quantnet-agent"
|
|
7
|
+
authors = [
|
|
8
|
+
{ name="ESnet", email="quantum@es.net" },
|
|
9
|
+
]
|
|
10
|
+
description = "The QN Agent for Quant-Net Control Plane"
|
|
11
|
+
readme = "README.md"
|
|
12
|
+
requires-python = ">=3.10"
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Programming Language :: Python :: 3",
|
|
15
|
+
"Operating System :: OS Independent",
|
|
16
|
+
]
|
|
17
|
+
license = "BSD-3-Clause-LBNL"
|
|
18
|
+
license-files = ["LICEN[CS]E*"]
|
|
19
|
+
dynamic = [
|
|
20
|
+
"version",
|
|
21
|
+
"dependencies"
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[project.urls]
|
|
25
|
+
Homepage = "https://github.com/quant-net/quant-net-agent"
|
|
26
|
+
|
|
27
|
+
[tool.setuptools.dynamic]
|
|
28
|
+
dependencies = {file = ["requirements.txt"]}
|
|
29
|
+
version = {attr = "quantnet_agent.__version__"}
|
|
30
|
+
|
|
31
|
+
[tool.setuptools.packages.find]
|
|
32
|
+
include = ["quantnet_agent", "quantnet_agent.*"]
|
|
33
|
+
|
|
34
|
+
[project.scripts]
|
|
35
|
+
quantnet_agent = "quantnet_agent.cli:main"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.0.0"
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import socket
|
|
2
|
+
import click
|
|
3
|
+
import sys
|
|
4
|
+
from quantnet_agent.service import QuantnetAgent
|
|
5
|
+
from quantnet_agent.common import Constants, Config
|
|
6
|
+
from quantnet_agent.common.logging import setup_logging
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@click.command("Quantnet Agent")
|
|
10
|
+
@click.option("-c",
|
|
11
|
+
"--config",
|
|
12
|
+
default=Constants.DEFAULT_CONFIG_FILE,
|
|
13
|
+
help="Main configuration file",
|
|
14
|
+
show_default=True)
|
|
15
|
+
@click.option("-n",
|
|
16
|
+
"--node-config",
|
|
17
|
+
default=None,
|
|
18
|
+
help="Node configuration file",
|
|
19
|
+
show_default=True)
|
|
20
|
+
@click.option("-a",
|
|
21
|
+
"--agent_id",
|
|
22
|
+
default=socket.getfqdn(),
|
|
23
|
+
help="Specify an agent identifier",
|
|
24
|
+
show_default=True)
|
|
25
|
+
@click.option("--mq-broker-host",
|
|
26
|
+
"mq_broker_host",
|
|
27
|
+
type=str,
|
|
28
|
+
help="Message queue broker host",
|
|
29
|
+
show_default=True)
|
|
30
|
+
@click.option("--mq-broker-port",
|
|
31
|
+
"mq_broker_port",
|
|
32
|
+
type=int,
|
|
33
|
+
help="Message queue broker port",
|
|
34
|
+
show_default=True)
|
|
35
|
+
@click.option("-d",
|
|
36
|
+
"--debug",
|
|
37
|
+
is_flag=True,
|
|
38
|
+
show_default=True,
|
|
39
|
+
default=False,
|
|
40
|
+
help="Enable debug logging")
|
|
41
|
+
@click.option("--interpreter-path",
|
|
42
|
+
"interpreter_path",
|
|
43
|
+
type=str,
|
|
44
|
+
help="Location of additional command interpreters",
|
|
45
|
+
show_default=True)
|
|
46
|
+
@click.option("--schema-path",
|
|
47
|
+
"schema_path",
|
|
48
|
+
type=str,
|
|
49
|
+
help="Specify a path containing additional schema files",
|
|
50
|
+
show_default=True
|
|
51
|
+
)
|
|
52
|
+
def main(config,
|
|
53
|
+
agent_id,
|
|
54
|
+
node_config,
|
|
55
|
+
mq_broker_host,
|
|
56
|
+
mq_broker_port,
|
|
57
|
+
debug,
|
|
58
|
+
interpreter_path,
|
|
59
|
+
schema_path):
|
|
60
|
+
cobj = Config(config,
|
|
61
|
+
node_config,
|
|
62
|
+
debug,
|
|
63
|
+
agent_id,
|
|
64
|
+
mq_broker_host,
|
|
65
|
+
mq_broker_port,
|
|
66
|
+
interpreter_path,
|
|
67
|
+
schema_path)
|
|
68
|
+
|
|
69
|
+
if cobj.node_file is None:
|
|
70
|
+
print("No node configuration file specified. Use --node-config (-n) to provide one.")
|
|
71
|
+
sys.exit(1)
|
|
72
|
+
|
|
73
|
+
setup_logging(cobj)
|
|
74
|
+
|
|
75
|
+
agent = QuantnetAgent(cobj)
|
|
76
|
+
agent.run()
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
if __name__ == "__main__":
|
|
80
|
+
sys.exit(main()) # pragma: no cover
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import logging
|
|
3
|
+
import configobj
|
|
4
|
+
import json
|
|
5
|
+
from quantnet_agent.common.constants import Constants
|
|
6
|
+
|
|
7
|
+
log = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_config(config_file):
|
|
11
|
+
config_files = []
|
|
12
|
+
if config_file:
|
|
13
|
+
config_files.append(config_file)
|
|
14
|
+
if "QUANTNET_HOME" in os.environ:
|
|
15
|
+
config_files.append(f"{os.environ['QUANTNET_HOME']}/etc/agent.cfg")
|
|
16
|
+
else:
|
|
17
|
+
config_files.append("/etc/quantnet/agent.cfg")
|
|
18
|
+
|
|
19
|
+
for cf in config_files:
|
|
20
|
+
try:
|
|
21
|
+
config = configobj.ConfigObj(cf)
|
|
22
|
+
except IOError:
|
|
23
|
+
continue
|
|
24
|
+
return config
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class Config:
|
|
28
|
+
def __init__(
|
|
29
|
+
self,
|
|
30
|
+
config_file: str = None,
|
|
31
|
+
node_file: str = None,
|
|
32
|
+
debug: bool = False,
|
|
33
|
+
agent_id: str = None,
|
|
34
|
+
mq_broker_host: str = None,
|
|
35
|
+
mq_broker_port: int = None,
|
|
36
|
+
interpreter_path: str = None,
|
|
37
|
+
schema_path: str = None,
|
|
38
|
+
):
|
|
39
|
+
self._config = None
|
|
40
|
+
self.devices = {}
|
|
41
|
+
|
|
42
|
+
self._config = get_config(config_file)
|
|
43
|
+
|
|
44
|
+
if not self._config:
|
|
45
|
+
log.warning("No configuration file found, continuing with defaults")
|
|
46
|
+
|
|
47
|
+
if node_file:
|
|
48
|
+
self.node_file = node_file
|
|
49
|
+
else:
|
|
50
|
+
self.node_file = self.config_get("agent", "node_file", raise_exception=False)
|
|
51
|
+
|
|
52
|
+
if mq_broker_host:
|
|
53
|
+
self.mq_broker_host = mq_broker_host
|
|
54
|
+
else:
|
|
55
|
+
self.mq_broker_host = self.config_get("mq", "host", default="127.0.0.1")
|
|
56
|
+
|
|
57
|
+
if mq_broker_port:
|
|
58
|
+
self.mq_broker_port = mq_broker_port
|
|
59
|
+
else:
|
|
60
|
+
self.mq_broker_port = self.config_get("mq", "port", default="1883")
|
|
61
|
+
|
|
62
|
+
self.threads = int(self.config_get("agent", "threads", default=8))
|
|
63
|
+
|
|
64
|
+
if debug:
|
|
65
|
+
self.debug = debug
|
|
66
|
+
else:
|
|
67
|
+
self.config_get("agent", "debug", default=False)
|
|
68
|
+
|
|
69
|
+
if agent_id:
|
|
70
|
+
self.cid = agent_id
|
|
71
|
+
else:
|
|
72
|
+
try:
|
|
73
|
+
self.cid = self.config_get("agent", "agent_id")
|
|
74
|
+
except Exception:
|
|
75
|
+
self.cid = None
|
|
76
|
+
|
|
77
|
+
if interpreter_path:
|
|
78
|
+
self.interpreter_path = interpreter_path
|
|
79
|
+
else:
|
|
80
|
+
self.interpreter_path = self.config_get("interpreters", "path", raise_exception=False)
|
|
81
|
+
|
|
82
|
+
if "protocols" in self._config and len(self._config["protocols"]) > 0:
|
|
83
|
+
if self.interpreter_path is None:
|
|
84
|
+
raise Exception("Interpreter location for protocols is not found")
|
|
85
|
+
self.proto_plugins = self._config["protocols"]
|
|
86
|
+
else:
|
|
87
|
+
self.proto_plugins = {}
|
|
88
|
+
|
|
89
|
+
if schema_path:
|
|
90
|
+
self.schema_path = schema_path
|
|
91
|
+
else:
|
|
92
|
+
self.schema_path = self.config_get("schemas", "path", raise_exception=False)
|
|
93
|
+
|
|
94
|
+
if "devices" in self._config:
|
|
95
|
+
self.devices = self._config["devices"]
|
|
96
|
+
|
|
97
|
+
self.tasks = []
|
|
98
|
+
self.task_properties = {}
|
|
99
|
+
|
|
100
|
+
if "tasks" in self._config:
|
|
101
|
+
for task, property in self._config["tasks"].items():
|
|
102
|
+
try:
|
|
103
|
+
if type(property) is configobj.Section:
|
|
104
|
+
with open(os.path.join(Constants.DEFAULT_TASK_PATH, property["path"]), "r") as file:
|
|
105
|
+
calibration_task = json.load(file)
|
|
106
|
+
if float(calibration_task["Periodicity"]) <= Constants.SLOTSIZE.total_seconds():
|
|
107
|
+
raise Exception(
|
|
108
|
+
f"Task {task} interval is too short."
|
|
109
|
+
"It should be larger than the TDMA slot size "
|
|
110
|
+
f"{Constants.SLOTSIZE.total_seconds() * 1e3 }"
|
|
111
|
+
)
|
|
112
|
+
self.tasks.append(calibration_task)
|
|
113
|
+
else:
|
|
114
|
+
self.task_properties[task] = property
|
|
115
|
+
except Exception as e:
|
|
116
|
+
log.error(f"Cannot load local task {task} : {e}")
|
|
117
|
+
|
|
118
|
+
def config_get(self, section, option, raise_exception=True, default=None, check_config_table=True):
|
|
119
|
+
"""
|
|
120
|
+
Return the string value for a given option in a section
|
|
121
|
+
|
|
122
|
+
:param section: the named section.
|
|
123
|
+
:param option: the named option.
|
|
124
|
+
:param raise_exception: Boolean to raise or not NoOptionError or NoSectionError.
|
|
125
|
+
:param default: the default value if not found.
|
|
126
|
+
:param check_config_table: if not set, avoid looking at config table
|
|
127
|
+
.
|
|
128
|
+
:returns: the configuration value.
|
|
129
|
+
"""
|
|
130
|
+
try:
|
|
131
|
+
return self._config[section][option]
|
|
132
|
+
except (configobj.ConfigObjError, KeyError) as err:
|
|
133
|
+
if raise_exception and default is None:
|
|
134
|
+
raise err
|
|
135
|
+
return default
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from datetime import timedelta
|
|
3
|
+
import quantnet_agent
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Constants:
|
|
7
|
+
DEFAULT_CONFIG_FILE = "./config/agent.cfg"
|
|
8
|
+
DEFAULT_NODE_CONFIG_FILE = "./config/conf-alice.json"
|
|
9
|
+
DEFAULT_LOGGING_CONFIG_FILE = "./config/logging.conf"
|
|
10
|
+
DEFAULT_INTERPRETERS = {
|
|
11
|
+
"scheduler": "scheduler.py",
|
|
12
|
+
"calibration": "calibration.py",
|
|
13
|
+
"experiment": "exp_framework.py",
|
|
14
|
+
}
|
|
15
|
+
DEFAULT_TASK_PATH = os.path.join(os.path.dirname(os.path.dirname(quantnet_agent.__file__)), "config/")
|
|
16
|
+
DEFAULT_TASK_INTERPRETER = os.path.join(
|
|
17
|
+
os.path.dirname(quantnet_agent.__file__), "hal/interpreter/calibration_interpreter.py"
|
|
18
|
+
)
|
|
19
|
+
DEFAULT_TASK_NS = "quantnet_agent.task"
|
|
20
|
+
HEARTBEAT_INTERVAL = 10
|
|
21
|
+
REGISTRATION_RETRY_INTERVAL = 10
|
|
22
|
+
MAX_TIMESLOTS = 20000
|
|
23
|
+
SLOTSIZE = timedelta(milliseconds=100)
|
|
24
|
+
SCHEDULER_GRACE_PERIOD = timedelta(milliseconds=50)
|
|
25
|
+
# TODO: Check SCHEDULER_GRACE_PERIOD < SLOTSIZE * MAX_TIMESLOTS
|
|
26
|
+
UPDATE_INTERVAL = SLOTSIZE * MAX_TIMESLOTS / 2
|
|
27
|
+
# TODO: Check if update_interval is appropriate
|
|
28
|
+
DAG_CHECK_INTERVAL = timedelta(milliseconds=1000)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import logging
|
|
4
|
+
import logging.config
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def quantnet_log_formatter(cobj=None):
|
|
8
|
+
config_logformat = cobj.config_get(
|
|
9
|
+
"common",
|
|
10
|
+
"logformat",
|
|
11
|
+
raise_exception=False,
|
|
12
|
+
default="{asctime} {name:<29} {process} {levelname:>8} {message}",
|
|
13
|
+
)
|
|
14
|
+
return logging.Formatter(fmt=config_logformat, style='{')
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def setup_default_logging(cobj=None):
|
|
18
|
+
"""
|
|
19
|
+
Configures the logging by setting the output stream to stdout and
|
|
20
|
+
configures log level and log format.
|
|
21
|
+
"""
|
|
22
|
+
config_loglevel = getattr(logging, cobj.config_get("common", "loglevel",
|
|
23
|
+
raise_exception=False, default="INFO").upper())
|
|
24
|
+
|
|
25
|
+
stdouthandler = logging.StreamHandler(stream=sys.stdout)
|
|
26
|
+
stdouthandler.setFormatter(quantnet_log_formatter(cobj))
|
|
27
|
+
stdouthandler.setLevel(config_loglevel)
|
|
28
|
+
logging.basicConfig(level=config_loglevel, handlers=[stdouthandler])
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def setup_logging(cobj=None):
|
|
32
|
+
"""
|
|
33
|
+
Configures the logging by setting the output stream to stdout and
|
|
34
|
+
configures log level and log format.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
configfiles = list()
|
|
38
|
+
|
|
39
|
+
if cobj:
|
|
40
|
+
logging_config_path = cobj.config_get("common", "logging_config", raise_exception=False, default=None)
|
|
41
|
+
if logging_config_path:
|
|
42
|
+
configfiles.append(logging_config_path)
|
|
43
|
+
|
|
44
|
+
for i in ["QUANTNET_HOME", "VIRTUAL_ENV"]:
|
|
45
|
+
if i in os.environ:
|
|
46
|
+
configfiles.append(f"{os.environ[i]}/etc/logging.conf")
|
|
47
|
+
configfiles.append("/opt/quantnet/etc/logging.conf")
|
|
48
|
+
|
|
49
|
+
has_config = False
|
|
50
|
+
for configfile in configfiles:
|
|
51
|
+
try:
|
|
52
|
+
logging.config.fileConfig(configfile, disable_existing_loggers=False)
|
|
53
|
+
has_config = True
|
|
54
|
+
except Exception:
|
|
55
|
+
has_config = False
|
|
56
|
+
if has_config:
|
|
57
|
+
break
|
|
58
|
+
|
|
59
|
+
if not has_config and cobj:
|
|
60
|
+
setup_default_logging(cobj)
|