Actions sortantes
Activer une action sortante, approuver une demande, lire son historique, activer ou désactiver la sortie sur liaison, et réconcilier une action à l'issue inconnue.
Ce guide couvre le côté opérateur des actions déclarées d'une source de données du runtime de connecteurs — la seule façon pour un connecteur d'écrire, invoquer ou publier vers un fournisseur ou un véhicule. Tout ici est désactivé jusqu'à ce qu'un administrateur d'organisation l'active, action par action.
Désactivé par défaut, deux verrous séparés. Une action déclarée n'envoie rien jusqu'à ce que (1) un administrateur active cette définition d'action exacte, et (2) si l'action l'exige, un approbateur admette la demande spécifique. Pour une action à destination link (une commande MAVLink vers un véhicule), un troisième interrupteur, au niveau du déploiement — ACTION_LINK_EGRESS_ENABLED, Helm security.actionAuthority.linkEgressEnabled — doit aussi lire "true" sur api-ontology, sur api-ingestion et sur API Platform, sinon aucune demande en mode liaison n'est jamais revendiquée ni envoyée, quelle que soit l'activation ou l'approbation.
Activer une action déclarée
Le manifeste d'une source de données déclare ses actions ; aucune ne peut envoyer quoi que ce soit avant d'être activée.
Un administrateur de l'organisation peut le faire dans Analytics → Ontologie → Actions. L'onglet liste chaque action que déclarent les sources de données installées, avec sa source, son empreinte de définition, et si elle est activée et par qui. Activer et Désactiver y soumettent les appels du noyau décrits sous Soumettre l'appel ci-dessous ; les étapes sont les mêmes dans les deux cas.
- Confirmez la définition de l'action dans la source installée — nom de l'opération, version, entrée de la cible, et si elle porte
requiresApproval: true. L'activation se lie à cette empreinte de définition exacte : si l'extension est mise à jour et que la définition de l'action change, réactivez-la sous la nouvelle empreinte. - Activez-la (le bouton Activer de l'onglet, ou
action.catalog.enablepour la source et l'action). C'est une opération réservée aux administrateurs d'organisation — un membre de l'organisation sans ce rôle est refusé avant que quoi que ce soit ne soit enregistré. - L'activation et l'empreinte à laquelle elle est liée sont écrites dans la même décision auditée qui journalise toute autre écriture du noyau : qui a activé quoi, et quand.
Pour retirer une action du service, soumettez action.catalog.disable de la même manière, en nommant la source, l'identifiant de l'action, sa version d'opération et une raison. Une action désactivée refuse immédiatement toute nouvelle demande. Une demande déjà en file au moment où l'action est désactivée, ou où sa définition change, est expirée au moment où elle est remise au dispatch, et n'est pas envoyée.
Une demande est dispatchée sous un mandat qui vit pendant le expirySeconds déclaré par l'action elle-même (au plus 300). Un mandat non utilisé à temps expire, et la demande avec lui, sans envoi.
Soumettre l'appel
L'onglet Actions est la manière habituelle de faire l'un ou l'autre appel. Aucun des deux n'a d'opération API Platform. Ce sont des actions du noyau sur api-ontology, POST /api/ontology/kernel/actions, qui n'admet qu'un appelant interne vérifié à l'intérieur du maillage de services — l'ingress retire de chaque requête externe les en-têtes d'identité qu'elle lit. L'appelant porte l'administrateur pour lequel il agit dans les en-têtes on-behalf-of : x-on-behalf-of-user-id, x-on-behalf-of-org-id, x-on-behalf-of-workspace-id et x-on-behalf-of-workspace-env-id.
{
"actionType": "action.catalog.enable",
"idempotencyKey": "<un UUID neuf>",
"input": {
"sourceKey": "<la clé de la source installée>",
"action": { "id": "…", "operation": { "name": "…", "version": 1 }, "…": "…" }
}
}input.action est la définition complète de l'action, copiée telle quelle depuis l'instantané de manifeste de la source installée — pas depuis un fichier de manifeste plus récent, ni écrite à la main. L'activation se lie à l'empreinte de cette définition : une définition qui diffère sur un seul champ active une action que personne ne peut demander, et la vraie demande est alors refusée comme non activée.
Activer une action ne contourne pas l'approbation. Une action requiresApproval: true retient toujours chaque demande au verrou d'approbation ci-dessous, même une fois activée.
Approuver une demande
Une demande pour une action déclarée arrive par l'opération action.tasking.dispatch d'API Platform (POST /api/platform/v1/action/tasking/dispatch), qui nomme la source installée, sa version de descripteur, l'action et ses paramètres. Si l'action exige une approbation, la première soumission enregistre une demande d'approbation liée à cette demande exacte et répond qu'une approbation est requise. Rien n'est encore mis en file. L'activation est vérifiée lorsque la demande est validée, avant qu'aucune ligne sortante ne soit écrite : une action non activée est refusée à ce moment-là, ce qui, pour une action qui exige une approbation, est la nouvelle soumission approuvée, pas la première.
- Trouvez la demande en attente dans Analytics → Ontologie → Approbations. Elle affiche l'action, le demandeur, l'échéance de l'approbation, les cibles et les paramètres (un paramètre que vous ne pouvez pas lire est masqué).
- Approuvez ou refusez. La décision porte l'empreinte exacte de la demande que vous avez examinée : l'onglet l'envoie pour vous, et un appelant direct de l'API la lit dans l'approbation en attente et la cite en retour. Une approbation vaut pour la seule demande exacte examinée — jamais « ce qui est en attente sous cet identifiant » — de sorte qu'une demande qui a changé après avoir été montrée à l'approbateur ne peut pas être approuvée en citant une ancienne empreinte.
- Le demandeur que le relecteur ne doit pas aussi être est l'acteur vérifié du noyau — jamais un champ d'identité de service que la demande porte par ailleurs — de sorte qu'une demande soumise via un compte de service est toujours approuvée ou refusée par un humain distinct de celui qui se trouve derrière cette soumission. L'onglet Approbations n'affiche aucun bouton de décision sur votre propre demande.
- Un refus porte une raison (obligatoire, jusqu'à 2048 caractères) et termine la demande.
- Après une approbation, le demandeur soumet à nouveau la même demande, avec la même clé d'idempotence, avant l'échéance de l'approbation. Cette soumission consomme l'approbation et met l'action en file : une approbation admet exactement une demande. Une approbation non utilisée avant son échéance expire, et la demande exige alors une nouvelle clé.
Chaque approbation ou refus est journalisé de la même manière qu'une décision d'activation : un reçu DECISION nommant la demande et l'issue, validé de manière atomique avec le changement d'état propre de la demande.
Lire l'historique et le statut d'une action
La ligne d'une demande sortante n'est écrite qu'une fois la demande admise, en une seule transaction qui la fait passer par requested → validated → prepared → awaiting_approval → authorized → queued (awaiting_approval seulement lorsque l'action exigeait une approbation). Une demande refusée avant cela n'a pas de ligne ; son refus figure dans le journal des décisions. À partir de queued, elle passe par queued → dispatching → sent → accepted / in_progress / rejected → completed, se termine en expired si le dispatcher la refuse avant l'envoi ou si elle est restée en queued plus longtemps que son expirySeconds déclaré (motif queue_deadline_passed), ou en outcome_unknown lorsqu'aucune réponse ne la règle avant l'expiration de son autorisation, ou qu'aucune réponse finale ne suit un accusé de réception dans les cinq minutes (une action correlation: "none" se termine à sent, état final pour elle). La réconciliation fait ensuite passer une ligne outcome_unknown à reconciled_succeeded ou reconciled_failed.
- Le statut d'une demande est l'état actuel de la ligne au moment où vous le lisez :
queuedou au-delà. - L'historique est le
lifecycle_historypropre à la ligne (chaque changement de statut ci-dessus, avec son heure et sa raison) et son nombre de tentatives (un réenvoi en ajoute une), plus les reçus DECISION de l'activation, de l'approbation et de la réconciliation, et l'audit de chaque mandat émis lors de la revendication.
Analytics → Ontologie → Historique des actions liste les demandes sortantes de l'espace de travail, les plus récentes d'abord, filtrées par statut, cible ou source, avec pour chaque ligne son statut, son demandeur, sa cible et ses paramètres. Vous voyez les paramètres de vos propres demandes ; un administrateur de l'organisation voit ceux de toutes les lignes, et peut y réconcilier une ligne outcome_unknown. L'onglet lit GET /kernel/action-history d'api-ontology. Le journal de décision garde les reçus d'activation, d'approbation et de réconciliation.
Activer ou désactiver la sortie sur liaison
ACTION_LINK_EGRESS_ENABLED est l'interrupteur, à l'échelle du déploiement, pour chaque action sortante à destination link — le seul type qui puisse envoyer une commande MAVLink réelle à un véhicule. Deux charges de travail la lisent, et toutes deux doivent concorder :
- api-ontology la lit à chaque revendication : désactivée, une ligne
linken file n'est jamais remise à un dispatcher. - api-ingestion la lit une fois au démarrage pour décider si son dispatcher est relié aux liaisons tenues, puis à nouveau avant chaque envoi. L'activer exige donc un redémarrage d'api-ingestion.
La valeur Helm security.actionAuthority.linkEgressEnabled (par défaut false) définit ACTION_LINK_EGRESS_ENABLED=true sur les deux Deployments à la fois, et la modifier redémarre les deux. Définissez-la via le chart plutôt qu'à la main sur chaque charge de travail, afin que les deux ne puissent pas diverger.
| Paramètre | Effet |
|---|---|
ACTION_LINK_EGRESS_ENABLED non défini ou toute valeur autre que "true" (par défaut) | Une demande à destination link est toujours admise et mise en file, mais jamais revendiquée : elle n'envoie rien. Elle n'expire pas : elle reste en file, et devient revendicable dès que la sortie sur liaison est activée. Les destinations non-link (simulation) ne sont pas affectées — et ne le sont pas non plus dans l'autre sens, puisque la sortie réelle pour les destinations simulation est désactivée dans le code, pas par cet interrupteur. |
ACTION_LINK_EGRESS_ENABLED=true sur les deux charges de travail | Une demande à destination link en file peut être revendiquée et envoyée sur une liaison signée que ce déploiement tient, toujours conditionnée par la liste blanche de commandes et le bail propre de la liaison. L'activation et l'approbation ont été vérifiées lors de sa mise en file. |
Le dispatcher sortant est un interrupteur séparé, ACTION_DISPATCH_ENABLED (désactivé par défaut, Helm apiIngestion.actionDispatch.enabled) — l'hôte api-ingestion qui revendique les actions dues, libère leur justificatif et envoie. api-ontology signe les mandats avec la clé privée de ACTION_AUTHORITY_SIGNING_JWK (Helm security.actionAuthority.signingKey.existingSecret) ; api-ingestion et API Platform les vérifient avec les clés publiques de ACTION_AUTHORITY_VERIFICATION_JWKS (Helm security.actionAuthority.verificationKeys.existingSecret ; clé actuelle et précédente, pour la rotation). Le chart refuse de rendre le dispatcher sans les deux Secrets, et api-ingestion refuse de démarrer avec le dispatcher activé et sans clés publiques, de sorte qu'une rotation de clé est un changement planifié et vérifié, jamais silencieux.
Une demande à destination link mise en file pendant que la sortie sur liaison était désactivée attend au plus l'expirySeconds de son action à compter de son admission. Si la sortie sur liaison est activée dans ce délai, elle est revendiquée et envoyée, sauf si son action a été désactivée ou redéfinie depuis : celle-ci est alors expirée au dispatch. Passé ce délai, elle se termine en expired (queue_deadline_passed) et n'est jamais envoyée.
Pour activer la sortie sur liaison pour un déploiement :
- Confirmez que le dispatcher est activé et que les deux Secrets de clés sont définis, comme ci-dessus.
- Définissez
security.actionAuthority.linkEgressEnabled: truedans vos valeurs et mettez à niveau la release (par exemplehelm upgrade … --set security.actionAuthority.linkEgressEnabled=true). Le chart définitACTION_LINK_EGRESS_ENABLED=truesur api-ontology, api-ingestion et API Platform et redémarre les trois. La libération d'identifiants d'API Platform consomme une seule fois l'autorisation de chaque commande de liaison et l'audite enaction.credential.releasedavant l'envoi de la commande ; tant qu'elle lit l'interrupteur désactivé, chaque commande de liaison expire sans envoi encredential_refused. - Confirmez que l'action spécifique que vous visez est activée (
action.catalog.enable) et que sa commande est sur la liste blanche — aujourd'hui, seulementMAV_CMD_SET_MESSAGE_INTERVAL. Toute autre commande MAVLink est refusée avant même d'être encodée, indépendamment de cet interrupteur. La source de la liaison doit aussi être fixée sur le dialecte MAVLink étendu, celui qui définit COMMAND_LONG et COMMAND_ACK : une demande sur une liaison fixée sur tout autre dialecte est refusée aveclink_dialect_lacks_commands, jamais envoyée et jamais simulée. Et la liaison doit être signée (signing: 'signed-required') : une liaison non signée reste en réception seule, et une commande pour elle est refusée aveclink_not_held. - Pour la désactiver à nouveau, définissez
security.actionAuthority.linkEgressEnabled: false(la valeur par défaut) et mettez à niveau la release. Une lignelinkpas encore revendiquée reste en file jusqu'à ce que sonexpirySecondsà compter de l'admission soit écoulé, puis se termine enexpired, sans envoi. Une commande revendiquée mais pas encore envoyée expire au dispatch. Une commande déjà envoyée et en attente de son accusé de réception n'obtient plus de réessai ; si aucun accusé n'arrive, elle se règle enoutcome_unknownet doit être réconciliée ci-dessous.
Il n'existe pas de dérogation par locataire ou par action pour ACTION_LINK_EGRESS_ENABLED — c'est un seul interrupteur pour tout le déploiement. Délimitez ce qui peut réellement envoyer par ce que vous activez par action, pas en attendant de cet interrupteur une granularité qu'il n'a pas.
Réconcilier une action à l'issue inconnue
Une commande en mode liaison obtient des réessais bornés et adaptés au protocole de la même commande sous le même mandat en attendant l'accusé de réception du véhicule. Quand ces réessais sont épuisés sans accusé, la demande se règle en outcome_unknown — jamais silencieusement failed — et aucune action ultérieure sur cette même cible à la même destination n'est revendiquée pour envoi jusqu'à ce que celle-ci soit réconciliée : une nouvelle demande est toujours admise et mise en file, et attend. C'est délibéré : le véhicule a peut-être exécuté la commande et l'accusé a été perdu, ou la commande n'est peut-être jamais arrivée : personne sinon un opérateur disposant de preuves indépendantes ne peut dire laquelle, et la plateforme ne devinera pas.
- Identifiez la ligne
outcome_unknown(sa cible, son action et la dernière tentative) : filtrez Analytics → Ontologie → Historique des actions sur le statut Résultat inconnu. - Déterminez ce qui s'est réellement passé, à partir de preuves extérieures au runtime de connecteurs — une télémétrie montrant que le changement commandé a pris effet, un journal du véhicule, une observation directe.
- Enregistrez l'issue, avec le bouton Réconcilier de la ligne dans l'Historique des actions (administrateurs de l'organisation) ou en soumettant
action.outbound.reconcileen nommant la demande. La boîte de dialogue ne choisit aucune issue à votre place ; choisissez l'une de :succeeded— fait passer la ligne àreconciled_succeededet libère la retenue sur sa cible.failed— fait passer la ligne àreconciled_failedet libère la retenue sur sa cible.still_unknown— n'écrit aucun changement du tout ; la retenue sur la cible reste exactement comme elle était, et vous pouvez réconcilier à nouveau plus tard avec de meilleures preuves.
- Incluez une raison. L'appel est audité comme une décision d'approbation — un reçu DECISION nommant la demande et l'issue que vous avez enregistrée — même un appel
still_unknownqui ne change rien.
Seule une ligne actuellement outcome_unknown peut être réconciliée ; réconcilier répond exactement à « ce qui s'est réellement passé pour cette tentative ambiguë », jamais pour une ligne qui n'a jamais été ambiguë ou qui est déjà réconciliée.
Pour aller plus loin
- Vue d'ensemble du runtime de connecteurs — ce qu'est le runtime de connecteurs et comment le cycle de vie sortant s'assemble.
- Modes d'ingestion — Une liaison MAVLink sur UDP — la liaison entrante sur laquelle une action à destination
linkenvoie. - Sécurité → Modèle de permissions — le rôle d'administrateur qu'exigent
action.catalog.enable/disable. - Sécurité → Journalisation d'audit — où vivent les reçus DECISION et l'historique d'action sous-jacents à ce guide.