Skip to content

Commit 6b0a8ae

Browse files
authored
Merge pull request #41 from AmedeeBulle/tokens
Misc python & terraform updates
2 parents 5d6a089 + 73e0550 commit 6b0a8ae

File tree

14 files changed

+53
-33
lines changed

14 files changed

+53
-33
lines changed

samples/python/command-response/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ It will listen for commands by subscribing to topics ending in `/cmd` and acknow
1515
by sending a response.
1616
The script will terminate when it receives a _shutdown_ command or a keyboard interrupt (Control-C).
1717

18+
Notes:
19+
20+
- The MQTT client must connect with `clean_session` set to false. This informs the
21+
IoT Platform that the device accepts commands. The platform will also ensure messages
22+
are retained while the device is disconnected.
23+
- The command handler runs in a separate thread so that the on_message handler returns
24+
quickly and does not block the MQTT client loop.
25+
1826
## Prerequisites
1927

2028
Install the Python dependencies

samples/python/command-response/command-response.py

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import json
1414
import os
15+
import queue
1516
import sys
1617
import threading
1718
import time
@@ -39,12 +40,13 @@ def on_connect(client, userdata, flags, reason_code, properties=None):
3940
client.subscribe("#", qos=config.qos)
4041

4142

42-
# Callback for MQTT message received event.
43-
def on_message(client, userdata, message, properties=None):
44-
topic = message.topic
45-
payload = message.payload.decode()
46-
state = userdata
47-
if topic.endswith("/cmd"):
43+
# Command handler thread
44+
def command_handler():
45+
while True:
46+
try:
47+
topic, payload, state = command_handler_queue.get()
48+
except queue.ShutDown:
49+
break
4850
print(f"Received command on {topic}: {payload}")
4951
# Command handling logic goes here.
5052
# For this example, only the shutdown command is handled, which will
@@ -63,22 +65,36 @@ def on_message(client, userdata, message, properties=None):
6365
ack_msg = json.dumps(
6466
{"status": "acknowledged", "time": current_epoch_microseconds()}
6567
)
66-
state["ack_msg_info"].append(
67-
client.publish(topic=rsp_topic, payload=ack_msg, qos=config.qos)
68-
)
68+
rc_pub = client.publish(topic=rsp_topic, payload=ack_msg, qos=config.qos)
69+
rc_pub.wait_for_publish()
70+
print(f"Finished command handling for: {topic}")
71+
command_handler_queue.task_done()
72+
73+
74+
# Callback for MQTT message received event.
75+
def on_message(client, userdata, message, properties=None):
76+
topic = message.topic
77+
payload = message.payload.decode()
78+
state = userdata
79+
if topic.endswith("/cmd"):
80+
command_handler_queue.put((topic, payload, state))
6981

7082

7183
if config.auth_type not in ("basic", "cert"):
7284
raise ValueError("auth_type must be 'basic' or 'cert'")
7385

86+
# Initialize queue and start command handler thread
87+
command_handler_queue = queue.Queue()
88+
command_handler_thread = threading.Thread(target=command_handler)
89+
command_handler_thread.start()
90+
7491
client = mqtt.Client(
7592
client_id=config.client_id, # Ensure client_id is set for persistent sessions.
7693
clean_session=False, # Enable persistent session.
7794
protocol=mqtt.MQTTv311, # Use v311 unless v5 features are needed.
7895
callback_api_version=mqtt.CallbackAPIVersion.VERSION2, # type: ignore
7996
)
8097
state = {
81-
"ack_msg_info": [],
8298
"shutdown_event": threading.Event(),
8399
}
84100
client.user_data_set(state)
@@ -121,19 +137,14 @@ def on_message(client, userdata, message, properties=None):
121137
rc_pub.wait_for_publish()
122138
count += 1
123139
time.sleep(config.message_delay)
124-
# Drain ack_msg_info
125-
while state["ack_msg_info"]:
126-
state["ack_msg_info"].pop(0).wait_for_publish()
127140

128141
except KeyboardInterrupt:
129142
print("\nInterrupted by user. Exiting...")
130143

131-
# Wait to process any potential /cmd messages before exit.
132-
print("Waiting 2 seconds to process possible /cmd messages...")
133-
time.sleep(2)
134-
# Drain ack_msg_info
135-
while state["ack_msg_info"]:
136-
state["ack_msg_info"].pop(0).wait_for_publish()
144+
# Wait for the queue to drain
145+
print("Waiting for commands to be processed...")
146+
command_handler_queue.shutdown()
147+
command_handler_thread.join()
137148

138149
# Tear down the client and exit.
139150
client.loop_stop()

samples/python/manage-dt/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ Options:
162162
-d, --debug Debug mode
163163
--profile TEXT The profile in the config file to load.
164164
[default: wim-iot-fra]
165-
--auth [api_key|instance_principal|resource_principal]
165+
--auth [api_key|instance_principal|resource_principal|security_token]
166166
The type of auth to use for the API request.
167167
[default: api_key]
168168
--data-dir DIRECTORY Data directory [default: ./data]

samples/python/manage-dt/manage_dt/mdt_oci.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,6 @@ def get_oci_config(
8383
case "security_token":
8484
logger.debug("OCI authentication: Session Token")
8585
config = oci_config.from_file(profile_name=profile)
86-
if os.getenv("OCI_CLI_TENANCY"):
87-
logger.debug("Overriding tenancy OCID")
88-
config["tenancy"] = os.getenv("OCI_CLI_TENANCY")
8986
token_file = config["security_token_file"]
9087
token = None
9188
with open(token_file, "r") as f:

samples/python/query-db/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ Copy `config.distr.py` to `config.py` and set the following variables:
6565
- `db_token_scope`: The dbTokenScope property of your IoT Domain Group.
6666
- `iot_domain_short_name`: The hostname part of the deviceHost property of your IoT Domain.
6767
- `oci_auth_type`: The OCI Authentication type. Must be either "ConfigFileAuthentication"
68-
for API Key authentication or "InstancePrincipal".
68+
for API Key authentication, "InstancePrincipal" or "SecurityToken".
6969
- `oci_profile`: OCI CLI profile to use for token retrieval when using API Key authentication.
7070
- `row_count`: The number of rows retrieved by the sample queries.
7171
- `thick_mode`: Set to `True` to use the `oracledb` Thick mode driver.

samples/python/query-db/config.distr.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
# jq -r '.'data."device-host"' | split(".")[0]'
1717
iot_domain_short_name = "<Domain SHort Name>"
1818

19-
# OCI Authentication type. Must be either "ConfigFileAuthentication" or "InstancePrincipal"
19+
# OCI Authentication type. Must be either "ConfigFileAuthentication", "InstancePrincipal"
20+
# or "SecurityToken"
2021
# oci_auth_type = "ConfigFileAuthentication"
2122
oci_auth_type = "InstancePrincipal"
2223

samples/python/query-db/query_db.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ def get_blob(blob: oracledb.LOB) -> Tuple[str, str]:
8888
"auth_type": config.oci_auth_type,
8989
"scope": config.db_token_scope,
9090
}
91-
if config.oci_auth_type == "ConfigFileAuthentication":
91+
if config.oci_auth_type in ["ConfigFileAuthentication", "SecurityToken"]:
9292
token_based_auth["profile"] = config.oci_profile
9393

9494
extra_connect_params = {}

samples/python/queues/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ Copy `config.distr.py` to `config.py` and set the following variables:
7676
- `db_connect_string`: The `dbConnectionString` property of your IoT Domain Group.
7777
- `db_token_scope`: The `dbTokenScope` property of your IoT Domain Group.
7878
- `iot_domain_short_name`: The hostname part of the `deviceHost` property of your IoT Domain.
79-
- `oci_auth_type`: The OCI authentication type. Use "ConfigFileAuthentication"
80-
for API key authentication, or "InstancePrincipal".
79+
- `oci_auth_type`: The OCI Authentication type. Must be either "ConfigFileAuthentication"
80+
for API Key authentication, "InstancePrincipal" or "SecurityToken".
8181
- `oci_profile`: OCI CLI profile to use for token retrieval (API key authentication only).
8282
- `thick_mode`: Set to `True` to use the `oracledb` thick mode driver.
8383
- `subscriber_name`: Name of the durable subscriber for the `sub-norm` sample.

samples/python/queues/config.distr.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
# jq -r '.'data."device-host"' | split(".")[0]'
2323
iot_domain_short_name = "<Domain SHort Name>"
2424

25-
# OCI Authentication type. Must be either "ConfigFileAuthentication" or "InstancePrincipal"
25+
# OCI Authentication type. Must be either "ConfigFileAuthentication", "InstancePrincipal"
26+
# or "SecurityToken"
2627
# oci_auth_type = "ConfigFileAuthentication"
2728
oci_auth_type = "InstancePrincipal"
2829

samples/python/queues/sub-norm.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def db_connect() -> oracledb.Connection:
5252
"auth_type": config.oci_auth_type,
5353
"scope": config.db_token_scope,
5454
}
55-
if config.oci_auth_type == "ConfigFileAuthentication":
55+
if config.oci_auth_type in ["ConfigFileAuthentication", "SecurityToken"]:
5656
token_based_auth["profile"] = config.oci_profile
5757

5858
extra_connect_params = {}

0 commit comments

Comments
 (0)