Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
1b50cad
CI tests for bridgehead
jainrocks Apr 17, 2026
b67c88a
CI tests for bridgehead
jainrocks Apr 17, 2026
9fe99fb
CI tests for bridgehead
jainrocks Apr 17, 2026
bee4e7f
fixing CI tests
jainrocks Apr 17, 2026
e213e0e
Fix out-of-sync gencode changes causing test failures (#6)
jainrocks Apr 18, 2026
b40ddf4
bridgehead CI test fixes
jainrocks Apr 19, 2026
8966a2c
Merge branch 'master' of github.com:jainrocks/udmi into ci_bridgehead
jainrocks Apr 19, 2026
879557d
bridgehead CI test fixes
jainrocks Apr 19, 2026
4210645
bridgehead CI test fixes
jainrocks Apr 19, 2026
281f514
changes for mosquitto ACLs
jainrocks Apr 27, 2026
086b372
Merge branch 'faucetsdn:master' into master
jainrocks Apr 27, 2026
dd70d09
Merge branch 'master' of github.com:jainrocks/udmi into mosquitto_acl…
jainrocks Apr 27, 2026
b9cc6d8
changes for mosquitto ACLs
jainrocks Apr 28, 2026
9729a16
changes for mosquitto ACLs
jainrocks Apr 28, 2026
e0976dc
Merge branch 'faucetsdn:master' into master
jainrocks May 6, 2026
3965cdc
Merge branch 'faucetsdn:master' into master
jainrocks May 7, 2026
51bc5bf
pull from master
jainrocks May 7, 2026
c250391
mosquito ACL support changes
jainrocks May 7, 2026
3374a97
allow mosquitto group to perform writes to dynamic_security.json file
jainrocks May 8, 2026
32fc574
allow mosquitto group to perform writes to dynamic_security.json file
jainrocks May 8, 2026
a4128cd
changess for the permissions for the attach topic
jainrocks May 11, 2026
8a3d2da
changes for fixing the sequencer tests
jainrocks May 11, 2026
4e039f1
changes for fixing the sequencer tests
jainrocks May 11, 2026
7411228
changes for fixing the sequencer tests
jainrocks May 11, 2026
e0d3c53
changes for fixing the sequencer tests
jainrocks May 11, 2026
1f11228
changes for fixing the sequencer tests
jainrocks May 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion bin/mosquctl_client
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,23 @@ shift 2
source $UDMI_ROOT/etc/mosquitto_ctrl.sh

client_user=$client_id
role_name="role_${client_id//\//_}"

$MOSQUITTO_CTRL deleteClient $client_user || true
$MOSQUITTO_CTRL deleteRole $role_name || true

if [[ $client_pass != "--" ]]; then
$MOSQUITTO_CTRL createClient $client_user -p $client_pass -c $client_id
$MOSQUITTO_CTRL addClientRole $client_user device

$MOSQUITTO_CTRL createRole $role_name
$MOSQUITTO_CTRL addClientRole $client_user $role_name

$MOSQUITTO_CTRL addRoleACL $role_name subscribePattern "$client_id/config" allow
$MOSQUITTO_CTRL addRoleACL $role_name subscribePattern "$client_id/commands" allow
$MOSQUITTO_CTRL addRoleACL $role_name subscribePattern "$client_id/errors" allow
$MOSQUITTO_CTRL addRoleACL $role_name publishClientSend "$client_id/events/#" allow
$MOSQUITTO_CTRL addRoleACL $role_name publishClientSend "$client_id/state" allow
echo "Device $client_id registered correctly."
else
echo "Device $client_id deleted correctly."
fi
47 changes: 47 additions & 0 deletions bin/mosquctl_gateway
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/bin/bash -e

UDMI_ROOT=$(dirname $0)/..
source $UDMI_ROOT/etc/shell_common.sh
source $UDMI_ROOT/etc/mosquitto_ctrl.sh

if [[ $# != 3 ]]; then
echo Usage: $0 action gateway_id device_id
echo Actions: bind, unbind
false
fi

action=$1
gateway_id=$2
device_id=$3

role_name="role_${gateway_id//\//_}"

if [[ $action == "bind" ]]; then
echo Binding $device_id to gateway $gateway_id
# Create role if not exists (ignore error if exists)
$MOSQUITTO_CTRL createRole $role_name || true
# Add role to gateway client (ignore error if already added)
$MOSQUITTO_CTRL addClientRole $gateway_id $role_name || true

# Add ACLs
$MOSQUITTO_CTRL addRoleACL $role_name subscribePattern "$device_id/config" allow
$MOSQUITTO_CTRL addRoleACL $role_name subscribePattern "$device_id/commands" allow
$MOSQUITTO_CTRL addRoleACL $role_name subscribePattern "$device_id/errors" allow
$MOSQUITTO_CTRL addRoleACL $role_name publishClientSend "$device_id/events/#" allow
$MOSQUITTO_CTRL addRoleACL $role_name publishClientSend "$device_id/state" allow
$MOSQUITTO_CTRL addRoleACL $role_name publishClientSend "$device_id/attach" allow
echo "Binding successful for $device_id to gateway $gateway_id"
elif [[ $action == "unbind" ]]; then
echo Unbinding $device_id from gateway $gateway_id
# Remove ACLs
$MOSQUITTO_CTRL removeRoleACL $role_name subscribePattern "$device_id/config" || true
$MOSQUITTO_CTRL removeRoleACL $role_name subscribePattern "$device_id/commands" || true
$MOSQUITTO_CTRL removeRoleACL $role_name subscribePattern "$device_id/errors" || true
$MOSQUITTO_CTRL removeRoleACL $role_name publishClientSend "$device_id/events/#" || true
$MOSQUITTO_CTRL removeRoleACL $role_name publishClientSend "$device_id/state" || true
$MOSQUITTO_CTRL removeRoleACL $role_name publishClientSend "$device_id/attach" || true
echo "Unbinding successful for $device_id from gateway $gateway_id"
else
echo Unknown action: $action
false
fi
19 changes: 12 additions & 7 deletions bin/start_mosquitto
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,30 @@ if [[ ! -f $UDMI_FILE ]]; then
[[ $(whoami) == root ]] && echo user root >> $UDMI_FILE
fi

# Ensure the mosquitto group can write to the config directory (required for atomic configuration saves)
sudo chgrp $GROUP $ETC_DIR || true
sudo chmod 775 $ETC_DIR || true

if [[ ! -f $DYN_FILE ]]; then
echo Creating new $DYN_FILE
echo Configuring MQTT user: $AUTH_USER
sudo mosquitto_ctrl dynsec init $DYN_FILE $AUTH_USER $AUTH_PASS
[[ $(whoami) != root ]] && sudo chgrp $GROUP $DYN_FILE
sudo chmod 0660 $DYN_FILE
fi

# Ensure the dynamic security file is owned by the mosquitto group and is group-writable (restricted to owner and group only)
sudo chgrp $GROUP $DYN_FILE || true
sudo chmod 0660 $DYN_FILE || true

if [[ ! -f $PASS_FILE ]]; then
echo Creating $PASS_FILE
sudo touch $PASS_FILE
sudo chmod 0640 $PASS_FILE
[[ $(whoami) != root ]] && sudo chgrp $GROUP $PASS_FILE
sudo mosquitto_passwd -b ${PASS_FILE} ${AUTH_USER} ${AUTH_PASS}
fi

# Ensure the passwd file is owned by the mosquitto user and is strictly private (0600)
sudo chown mosquitto:mosquitto $PASS_FILE || true
sudo chmod 0600 $PASS_FILE || true

if [[ -n $(which systemctl) ]]; then
sudo systemctl restart mosquitto
else
Expand All @@ -62,9 +70,6 @@ else
echo Completed mosquitto startup.
fi

$MOSQUITTO_CTRL createRole device
$MOSQUITTO_CTRL addRoleACL device subscribePattern '/r/+/d/+/#' allow
$MOSQUITTO_CTRL addRoleACL device publishClientSend '/r/+/d/+/#' allow
$MOSQUITTO_CTRL createRole service
$MOSQUITTO_CTRL addRoleACL service subscribePattern '/r/+/d/+/#' allow
$MOSQUITTO_CTRL addRoleACL service publishClientSend '/r/+/d/+/#' allow
Expand Down
2 changes: 1 addition & 1 deletion bin/test_mosquitto
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ CLIENT_OPTS="-i $CLNT_ID -u $CLNT_USER -P $CLNT_PASS --cafile $CA_CERT --cert $C

$MOSQUITTO_CTRL deleteClient $CLNT_USER
$MOSQUITTO_CTRL createClient $CLNT_USER -p $CLNT_PASS -c $CLNT_ID
$MOSQUITTO_CTRL addClientRole $CLNT_USER device
$MOSQUITTO_CTRL addClientRole $CLNT_USER service

killall mosquitto_sub || true

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,19 @@ public static String hashedDeviceId(String registryId, String deviceId) {

private void bindDevicesToGateway(String registryId, String gatewayId, CloudModel cloudModel) {
Set<String> deviceIds = ImmutableSet.copyOf(cloudModel.gateway.proxy_ids);
deviceIds.forEach(deviceId ->
registryDeviceRef(registryId, deviceId).put(BOUND_TO_KEY, gatewayId));
deviceIds.forEach(deviceId -> {
registryDeviceRef(registryId, deviceId).put(BOUND_TO_KEY, gatewayId);
broker.bindGateway(clientId(registryId, gatewayId), clientId(registryId, deviceId));
});
}

private void unbindDevicesFromGateway(String registryId, String gatewayId,
CloudModel cloudModel) {
Set<String> deviceIds = ImmutableSet.copyOf(cloudModel.gateway.proxy_ids);
deviceIds.forEach(deviceId -> {
registryDeviceRef(registryId, deviceId).delete(BOUND_TO_KEY);
broker.unbindGateway(clientId(registryId, gatewayId), clientId(registryId, deviceId));
});
}

private void blockDevice(String registryId, String deviceId, CloudModel cloudModel) {
Expand Down Expand Up @@ -161,6 +172,11 @@ private void deleteDevice(String registryId, String deviceId, CloudModel cloudMo
properties.entries().keySet().forEach(properties::delete);
registryDevicesRef(registryId).delete(deviceId);
broker.authorize(clientId(registryId, deviceId), null);
String gatewayId = properties.get(BOUND_TO_KEY);

if (gatewayId != null) {
broker.unbindGateway(clientId(registryId, gatewayId), clientId(registryId, deviceId));
}
}

private CloudModel getReply(String registryId, String deviceId, CloudModel request,
Expand Down Expand Up @@ -339,6 +355,7 @@ public CloudModel modelDevice(String registryId, String deviceId, CloudModel clo
case DELETE -> deleteDevice(registryId, deviceId, cloudModel);
case MODIFY -> modifyDevice(registryId, deviceId, cloudModel);
case BIND -> bindDevicesToGateway(registryId, deviceId, cloudModel);
case UNBIND -> unbindDevicesFromGateway(registryId, deviceId, cloudModel);
case BLOCK -> blockDevice(registryId, deviceId, cloudModel);
default -> throw new RuntimeException("Unknown device operation " + operation);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ public interface ConnectionBroker {

Future<Void> addEventListener(String clientPrefix, Consumer<BrokerEvent> eventConsumer);

void bindGateway(String gatewayId, String deviceId);

void unbindGateway(String gatewayId, String deviceId);

/**
* Simple event for connection broker happenings.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public class MosquittoBroker extends ContainerBase implements ConnectionBroker {
private static final String UDMI_ROOT = System.getenv("UDMI_ROOT");
private static final String MOSQUCTL_CLIENT_FMT = UDMI_ROOT + "/bin/mosquctl_client %s %s";
private static final String MOSQUCTL_LOG_FMT = UDMI_ROOT + "/bin/mosquctl_log %s";
private static final String MOSQUCTL_GATEWAY_FMT = UDMI_ROOT + "/bin/mosquctl_gateway %s %s %s";
private static final long EXEC_TIMEOUT_SEC = 10;
private static final String REVOKE_PASSWORD = "--";
private static final Pattern LOG_MATCHER =
Expand Down Expand Up @@ -60,8 +61,7 @@ private void consumeStream(BufferedReader reader, Consumer<String> consumer) {
thread.start();
}

private void mosquctlClient(String clientId, String clientPass) {
String cmd = format(MOSQUCTL_CLIENT_FMT, clientId, clientPass);
private void executeCommand(String cmd) {
synchronized (MosquittoBroker.class) {
try {
info("Executing command %s", cmd);
Expand All @@ -77,6 +77,10 @@ private void mosquctlClient(String clientId, String clientPass) {
}
}

private void mosquctlClient(String clientId, String clientPass) {
executeCommand(format(MOSQUCTL_CLIENT_FMT, clientId, clientPass));
}

private void mosquctlLog(String clientPrefix, Consumer<BrokerEvent> eventConsumer) {
String cmd = format(MOSQUCTL_LOG_FMT, clientPrefix);
synchronized (MosquittoBroker.class) {
Expand Down Expand Up @@ -148,4 +152,15 @@ public Future<Void> addEventListener(String clientPrefix,
public void authorize(String clientId, String password) {
mosquctlClient(clientId, ofNullable(password).orElse(REVOKE_PASSWORD));
}

@Override
public void bindGateway(String gatewayId, String deviceId) {
executeCommand(format(MOSQUCTL_GATEWAY_FMT, "bind", gatewayId, deviceId));
}

@Override
public void unbindGateway(String gatewayId, String deviceId) {
info("Unbind device Id: %s from gateway Id: %s :%s", deviceId, gatewayId);
executeCommand(format(MOSQUCTL_GATEWAY_FMT, "unbind", gatewayId, deviceId));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@
import udmi.schema.Envelope.SubFolder;
import udmi.schema.ExecutionConfiguration;
import udmi.schema.GatewayModel;
import udmi.schema.IotAccess.IotProvider;
import udmi.schema.LinkExternalsModel;
import udmi.schema.Metadata;
import udmi.schema.SetupUdmiConfig;
Expand Down Expand Up @@ -1278,7 +1279,10 @@ private void bindGatewayDevices(Map<String, LocalDevice> localDevices) {
if (dryRun) {
System.err.printf("Dry run: would bind %s to %s%n", setOrSize(toBind), gatewayId);
} else {
cloudIotManager.bindDevices(toBind, gatewayId, true);
boolean isLocal =
cloudIotManager.executionConfiguration.iot_provider == IotProvider.MQTT
|| cloudIotManager.executionConfiguration.iot_provider == IotProvider.IMPLICIT;
cloudIotManager.bindDevices(isLocal ? proxyIds : toBind, gatewayId, true);
}
recordOperation(ModelOperation.BIND, toBind.size());
} catch (Exception e) {
Expand Down