openc3-cosmos-tool-docs 6.10.1 → 6.10.2
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.
- checksums.yaml +4 -4
- data/tools/staticdocs/404.html +2 -2
- data/tools/staticdocs/assets/css/{styles.9a220ac7.css → styles.6a21a146.css} +1 -1
- data/tools/staticdocs/assets/js/{019369f3.d7bbc5e1.js → 019369f3.622250b4.js} +1 -1
- data/tools/staticdocs/assets/js/{058ffc22.e446ff0d.js → 058ffc22.8edfaac4.js} +1 -1
- data/tools/staticdocs/assets/js/{0686a885.5b4c4b4d.js → 0686a885.9151d3f9.js} +1 -1
- data/tools/staticdocs/assets/js/{078dbab0.656de457.js → 078dbab0.09694602.js} +1 -1
- data/tools/staticdocs/assets/js/{0f5d161c.7e54cdcf.js → 0f5d161c.4c365bfd.js} +1 -1
- data/tools/staticdocs/assets/js/0ff569c9.7a4faa61.js +1 -0
- data/tools/staticdocs/assets/js/{10209fc9.b137dbd6.js → 10209fc9.dc70ea3f.js} +1 -1
- data/tools/staticdocs/assets/js/{103cc3be.ee6acb84.js → 103cc3be.c15dbb1d.js} +1 -1
- data/tools/staticdocs/assets/js/13196248.c70e8c44.js +1 -0
- data/tools/staticdocs/assets/js/{13c1b4e4.4c262e75.js → 13c1b4e4.c29d1c64.js} +1 -1
- data/tools/staticdocs/assets/js/1731.371fb57d.js +1 -0
- data/tools/staticdocs/assets/js/{1c0a0c05.ddb465d3.js → 1c0a0c05.35a848fc.js} +1 -1
- data/tools/staticdocs/assets/js/{2047b354.6cacf929.js → 2047b354.1fd954bf.js} +1 -1
- data/tools/staticdocs/assets/js/{22b3ac48.7b94bcf3.js → 22b3ac48.9afe5dd8.js} +1 -1
- data/tools/staticdocs/assets/js/26b8abb2.980a3452.js +1 -0
- data/tools/staticdocs/assets/js/{2bb7bf90.3bde2607.js → 2bb7bf90.aa9deeb1.js} +1 -1
- data/tools/staticdocs/assets/js/{2c15ad40.4b4b971e.js → 2c15ad40.5b907671.js} +1 -1
- data/tools/staticdocs/assets/js/3064.05d05a26.js +1 -0
- data/tools/staticdocs/assets/js/35398c5c.17c941ac.js +1 -0
- data/tools/staticdocs/assets/js/{3dd7ef3b.0221eef2.js → 3dd7ef3b.60465ff4.js} +1 -1
- data/tools/staticdocs/assets/js/{40365d27.41de4945.js → 40365d27.a658985c.js} +1 -1
- data/tools/staticdocs/assets/js/{411898ad.6f36be2d.js → 411898ad.9843564e.js} +1 -1
- data/tools/staticdocs/assets/js/42170351.0865881a.js +1 -0
- data/tools/staticdocs/assets/js/{43652efd.e2fc7748.js → 43652efd.6c00e2f7.js} +1 -1
- data/tools/staticdocs/assets/js/5191.15b90810.js +1 -0
- data/tools/staticdocs/assets/js/{53ca7c5b.eccd9100.js → 53ca7c5b.576d6c45.js} +1 -1
- data/tools/staticdocs/assets/js/{54d0d530.cec50ece.js → 54d0d530.2278fc39.js} +1 -1
- data/tools/staticdocs/assets/js/{567dad64.50613669.js → 567dad64.89733625.js} +1 -1
- data/tools/staticdocs/assets/js/{5738ba7a.cede7d7a.js → 5738ba7a.c1945cad.js} +1 -1
- data/tools/staticdocs/assets/js/{59ed27a4.1b2efe08.js → 59ed27a4.53f184ee.js} +1 -1
- data/tools/staticdocs/assets/js/{5b233ba7.9faed769.js → 5b233ba7.e3319d37.js} +1 -1
- data/tools/staticdocs/assets/js/{5bc719f6.789ebf64.js → 5bc719f6.2fc3c8f6.js} +1 -1
- data/tools/staticdocs/assets/js/{5c6ce5ec.16226a4e.js → 5c6ce5ec.87929366.js} +1 -1
- data/tools/staticdocs/assets/js/5e3ed378.dcffdeae.js +1 -0
- data/tools/staticdocs/assets/js/{5fe211ef.bfe87c27.js → 5fe211ef.e2df613c.js} +1 -1
- data/tools/staticdocs/assets/js/6317.78aef81b.js +4 -0
- data/tools/staticdocs/assets/js/6321.2b2e50c9.js +101 -0
- data/tools/staticdocs/assets/js/6831b732.5cffcb1b.js +1 -0
- data/tools/staticdocs/assets/js/{696b4199.7520348a.js → 696b4199.e21ac90d.js} +1 -1
- data/tools/staticdocs/assets/js/{6b210247.fc77f080.js → 6b210247.6948ce0a.js} +1 -1
- data/tools/staticdocs/assets/js/{6b65133b.f2b11b07.js → 6b65133b.9a650bf4.js} +1 -1
- data/tools/staticdocs/assets/js/{6f92e431.26f4227b.js → 6f92e431.42d18623.js} +1 -1
- data/tools/staticdocs/assets/js/{72c6d8a8.0b8c5d2f.js → 72c6d8a8.f72ab546.js} +1 -1
- data/tools/staticdocs/assets/js/{75e64983.8112c73c.js → 75e64983.e1b9bc7d.js} +1 -1
- data/tools/staticdocs/assets/js/8330.134a0142.js +1 -0
- data/tools/staticdocs/assets/js/{867640d5.6bc9ed72.js → 867640d5.a8e8538f.js} +1 -1
- data/tools/staticdocs/assets/js/{89e76475.6411e788.js → 89e76475.32c89b40.js} +1 -1
- data/tools/staticdocs/assets/js/{8b939c74.5e039b7a.js → 8b939c74.99379b35.js} +1 -1
- data/tools/staticdocs/assets/js/{8f7843ee.fb130406.js → 8f7843ee.e62c6e1f.js} +1 -1
- data/tools/staticdocs/assets/js/{9424f0b3.90296433.js → 9424f0b3.bf3ec778.js} +1 -1
- data/tools/staticdocs/assets/js/{964eb012.94a1dac1.js → 964eb012.4e5410df.js} +1 -1
- data/tools/staticdocs/assets/js/{97535711.3e76daa6.js → 97535711.b76a8c8c.js} +1 -1
- data/tools/staticdocs/assets/js/{99581c43.48391a19.js → 99581c43.c34f316a.js} +1 -1
- data/tools/staticdocs/assets/js/{9d6e81d0.c9e12517.js → 9d6e81d0.09ec34de.js} +1 -1
- data/tools/staticdocs/assets/js/{9fb6059a.2473a196.js → 9fb6059a.88b86038.js} +1 -1
- data/tools/staticdocs/assets/js/{a677c089.4e7df83d.js → a677c089.08bdd6d4.js} +1 -1
- data/tools/staticdocs/assets/js/{a9987364.5ca31d27.js → a9987364.f143fcf5.js} +1 -1
- data/tools/staticdocs/assets/js/a9b2dc27.307c7457.js +1 -0
- data/tools/staticdocs/assets/js/aa6b6c1b.daef5095.js +1 -0
- data/tools/staticdocs/assets/js/b062d239.09ce80e1.js +1 -0
- data/tools/staticdocs/assets/js/{b38a6d74.b0b07b64.js → b38a6d74.00258c8b.js} +1 -1
- data/tools/staticdocs/assets/js/{b4596165.8792340f.js → b4596165.fa18ea16.js} +1 -1
- data/tools/staticdocs/assets/js/b6d70f94.22bbfe27.js +1 -0
- data/tools/staticdocs/assets/js/{b9f60ba6.f2b60175.js → b9f60ba6.f6e2591d.js} +1 -1
- data/tools/staticdocs/assets/js/{bd0034eb.f33ae892.js → bd0034eb.b3071da1.js} +1 -1
- data/tools/staticdocs/assets/js/{c24eae19.4d25de93.js → c24eae19.4d680f8b.js} +1 -1
- data/tools/staticdocs/assets/js/{c956ad1e.38882e03.js → c956ad1e.fa55a414.js} +1 -1
- data/tools/staticdocs/assets/js/{cb8c3f08.7ca03d18.js → cb8c3f08.9d7767a0.js} +1 -1
- data/tools/staticdocs/assets/js/{cd879be4.f77d4fff.js → cd879be4.207fcb79.js} +1 -1
- data/tools/staticdocs/assets/js/cf1c01b8.85934be0.js +1 -0
- data/tools/staticdocs/assets/js/{d1b923aa.a5b3429d.js → d1b923aa.b31315e3.js} +1 -1
- data/tools/staticdocs/assets/js/d1bfc316.16fb4147.js +1 -0
- data/tools/staticdocs/assets/js/{d24bf9b6.f380debf.js → d24bf9b6.c8d15feb.js} +1 -1
- data/tools/staticdocs/assets/js/{d57a4b5d.7ce9d24e.js → d57a4b5d.90256479.js} +1 -1
- data/tools/staticdocs/assets/js/{d59d8a14.41f22286.js → d59d8a14.2ecf6a7b.js} +1 -1
- data/tools/staticdocs/assets/js/d5d77c37.1de06b83.js +1 -0
- data/tools/staticdocs/assets/js/{d66bf9c0.c87e9dc0.js → d66bf9c0.be6ef286.js} +1 -1
- data/tools/staticdocs/assets/js/{d8ca4191.b24de36d.js → d8ca4191.4cf3e03b.js} +1 -1
- data/tools/staticdocs/assets/js/d9b92eba.13b9d3a8.js +1 -0
- data/tools/staticdocs/assets/js/db8fa1d0.0714f6fa.js +1 -0
- data/tools/staticdocs/assets/js/{dbe31111.4f18bf2b.js → dbe31111.ae534424.js} +1 -1
- data/tools/staticdocs/assets/js/{dc5f7beb.d439e98e.js → dc5f7beb.28bc7f0f.js} +1 -1
- data/tools/staticdocs/assets/js/{e501b0d1.e7e284e5.js → e501b0d1.9b902145.js} +1 -1
- data/tools/staticdocs/assets/js/{f15615f1.7dcf0c73.js → f15615f1.7835e26e.js} +1 -1
- data/tools/staticdocs/assets/js/{f75a5f33.a7c7ff1d.js → f75a5f33.8fcf0643.js} +1 -1
- data/tools/staticdocs/assets/js/fd886806.efd66dbe.js +1 -0
- data/tools/staticdocs/assets/js/{main.81fa15db.js → main.355b79aa.js} +6 -6
- data/tools/staticdocs/assets/js/{runtime~main.e35f5fea.js → runtime~main.4a381777.js} +1 -1
- data/tools/staticdocs/docs/configuration/accessors.html +46 -46
- data/tools/staticdocs/docs/configuration/command.html +87 -87
- data/tools/staticdocs/docs/configuration/conversions.html +47 -47
- data/tools/staticdocs/docs/configuration/format.html +21 -21
- data/tools/staticdocs/docs/configuration/interfaces.html +55 -55
- data/tools/staticdocs/docs/configuration/limits-response.html +10 -10
- data/tools/staticdocs/docs/configuration/plugins.html +129 -124
- data/tools/staticdocs/docs/configuration/processors.html +15 -15
- data/tools/staticdocs/docs/configuration/protocols.html +66 -66
- data/tools/staticdocs/docs/configuration/ssl-tls.html +15 -15
- data/tools/staticdocs/docs/configuration/table.html +44 -44
- data/tools/staticdocs/docs/configuration/target.html +21 -21
- data/tools/staticdocs/docs/configuration/telemetry-screens.html +253 -253
- data/tools/staticdocs/docs/configuration/telemetry.html +83 -83
- data/tools/staticdocs/docs/configuration.html +2 -2
- data/tools/staticdocs/docs/development/curl.html +14 -14
- data/tools/staticdocs/docs/development/developing.html +16 -16
- data/tools/staticdocs/docs/development/json-api.html +15 -15
- data/tools/staticdocs/docs/development/log-structure.html +11 -11
- data/tools/staticdocs/docs/development/roadmap.html +4 -4
- data/tools/staticdocs/docs/development/streaming-api.html +24 -24
- data/tools/staticdocs/docs/development/testing.html +17 -17
- data/tools/staticdocs/docs/development.html +2 -2
- data/tools/staticdocs/docs/getting-started/cli.html +42 -42
- data/tools/staticdocs/docs/getting-started/generators.html +24 -24
- data/tools/staticdocs/docs/getting-started/gettingstarted.html +19 -19
- data/tools/staticdocs/docs/getting-started/installation.html +49 -19
- data/tools/staticdocs/docs/getting-started/key-concepts.html +20 -20
- data/tools/staticdocs/docs/getting-started/podman.html +23 -23
- data/tools/staticdocs/docs/getting-started/requirements.html +19 -19
- data/tools/staticdocs/docs/getting-started/upgrading.html +44 -44
- data/tools/staticdocs/docs/getting-started/util.html +25 -25
- data/tools/staticdocs/docs/getting-started.html +2 -2
- data/tools/staticdocs/docs/guides/bridges.html +14 -14
- data/tools/staticdocs/docs/guides/cfs.html +32 -32
- data/tools/staticdocs/docs/guides/custom-widgets.html +33 -33
- data/tools/staticdocs/docs/guides/dynamic-packets.html +7 -6
- data/tools/staticdocs/docs/guides/exposing-microservices.html +11 -11
- data/tools/staticdocs/docs/guides/little-endian-bitfields.html +4 -4
- data/tools/staticdocs/docs/guides/local-mode.html +13 -13
- data/tools/staticdocs/docs/guides/logging.html +9 -9
- data/tools/staticdocs/docs/guides/monitoring.html +18 -18
- data/tools/staticdocs/docs/guides/performance.html +10 -10
- data/tools/staticdocs/docs/guides/raspberrypi.html +4 -4
- data/tools/staticdocs/docs/guides/reference-architectures.html +6 -6
- data/tools/staticdocs/docs/guides/roles-permissions.html +29 -29
- data/tools/staticdocs/docs/guides/script-writing.html +75 -68
- data/tools/staticdocs/docs/guides/scripting-api.html +672 -667
- data/tools/staticdocs/docs/guides/troubleshooting.html +7 -7
- data/tools/staticdocs/docs/guides.html +2 -2
- data/tools/staticdocs/docs/meta/contributing.html +12 -12
- data/tools/staticdocs/docs/meta/licenses.html +9 -9
- data/tools/staticdocs/docs/meta/philosophy.html +3 -3
- data/tools/staticdocs/docs/meta/vulnerabilities.html +5 -5
- data/tools/staticdocs/docs/meta/xtce.html +12 -12
- data/tools/staticdocs/docs/meta.html +2 -2
- data/tools/staticdocs/docs/privacy.html +17 -17
- data/tools/staticdocs/docs/tools/admin.html +28 -28
- data/tools/staticdocs/docs/tools/autonomic.html +19 -19
- data/tools/staticdocs/docs/tools/bucket-explorer.html +11 -11
- data/tools/staticdocs/docs/tools/calendar.html +24 -24
- data/tools/staticdocs/docs/tools/cmd-sender.html +13 -13
- data/tools/staticdocs/docs/tools/cmd-tlm-server.html +24 -24
- data/tools/staticdocs/docs/tools/command-history.html +6 -6
- data/tools/staticdocs/docs/tools/command-queue.html +8 -8
- data/tools/staticdocs/docs/tools/data-extractor.html +23 -23
- data/tools/staticdocs/docs/tools/data-viewer.html +10 -10
- data/tools/staticdocs/docs/tools/handbooks.html +4 -4
- data/tools/staticdocs/docs/tools/limits-monitor.html +15 -15
- data/tools/staticdocs/docs/tools/log-explorer.html +9 -9
- data/tools/staticdocs/docs/tools/packet-viewer.html +10 -10
- data/tools/staticdocs/docs/tools/script-runner.html +36 -36
- data/tools/staticdocs/docs/tools/systemhealth.html +21 -21
- data/tools/staticdocs/docs/tools/table-manager.html +10 -10
- data/tools/staticdocs/docs/tools/tlm-grapher.html +20 -20
- data/tools/staticdocs/docs/tools/tlm-viewer.html +15 -15
- data/tools/staticdocs/docs/tools.html +2 -2
- data/tools/staticdocs/docs.html +11 -11
- data/tools/staticdocs/index.html +2 -2
- data/tools/staticdocs/lunr-index-1765917283926.json +1 -0
- data/tools/staticdocs/lunr-index.json +1 -1
- data/tools/staticdocs/markdown-page.html +3 -3
- data/tools/staticdocs/search-doc-1765917283926.json +1 -0
- data/tools/staticdocs/search-doc.json +1 -1
- metadata +92 -92
- data/tools/staticdocs/assets/js/0ff569c9.9566d390.js +0 -1
- data/tools/staticdocs/assets/js/1202.d22d6899.js +0 -101
- data/tools/staticdocs/assets/js/13196248.8bbc13cd.js +0 -1
- data/tools/staticdocs/assets/js/1596.e0bc0cb8.js +0 -1
- data/tools/staticdocs/assets/js/26b8abb2.237c47e9.js +0 -1
- data/tools/staticdocs/assets/js/3140.8b312c79.js +0 -1
- data/tools/staticdocs/assets/js/35398c5c.0f3180d9.js +0 -1
- data/tools/staticdocs/assets/js/42170351.3618f599.js +0 -1
- data/tools/staticdocs/assets/js/4581.bbe04eae.js +0 -4
- data/tools/staticdocs/assets/js/5e3ed378.9ad2dcd2.js +0 -1
- data/tools/staticdocs/assets/js/6831b732.1790429a.js +0 -1
- data/tools/staticdocs/assets/js/7399.857e78fe.js +0 -1
- data/tools/staticdocs/assets/js/9601.e8389133.js +0 -1
- data/tools/staticdocs/assets/js/a9b2dc27.1f8d5c81.js +0 -1
- data/tools/staticdocs/assets/js/aa6b6c1b.750dc927.js +0 -1
- data/tools/staticdocs/assets/js/b062d239.cd8e5784.js +0 -1
- data/tools/staticdocs/assets/js/b6d70f94.43a5cd5a.js +0 -1
- data/tools/staticdocs/assets/js/cf1c01b8.f5a9a237.js +0 -1
- data/tools/staticdocs/assets/js/d1bfc316.7c605bc5.js +0 -1
- data/tools/staticdocs/assets/js/d5d77c37.ae6fba94.js +0 -1
- data/tools/staticdocs/assets/js/d9b92eba.b08eeda4.js +0 -1
- data/tools/staticdocs/assets/js/db8fa1d0.a05e2bae.js +0 -1
- data/tools/staticdocs/assets/js/fd886806.4b383c00.js +0 -1
- data/tools/staticdocs/lunr-index-1765340262146.json +0 -1
- data/tools/staticdocs/search-doc-1765340262146.json +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";(self.webpackChunkdocs_openc3_com=self.webpackChunkdocs_openc3_com||[]).push([["6490"],{2588:function(e,s,n){n.r(s),n.d(s,{metadata:()=>i,default:()=>h,frontMatter:()=>l,contentTitle:()=>t,toc:()=>c,assets:()=>d});var i=JSON.parse('{"id":"guides/roles-permissions","title":"Roles and Permissions","description":"Understanding COSMOS Enterprise roles and access control","source":"@site/docs/guides/roles-permissions.md","sourceDirName":"guides","slug":"/guides/roles-permissions","permalink":"/tools/staticdocs/docs/guides/roles-permissions","draft":false,"unlisted":false,"editUrl":"https://github.com/OpenC3/cosmos/tree/main/docs.openc3.com/docs/guides/roles-permissions.md","tags":[],"version":"current","frontMatter":{"title":"Roles and Permissions","description":"Understanding COSMOS Enterprise roles and access control","sidebar_custom_props":{"myEmoji":"\u{1F510}"}},"sidebar":"defaultSidebar","previous":{"title":"Reference Architectures","permalink":"/tools/staticdocs/docs/guides/reference-architectures"},"next":{"title":"Script Writing Guide","permalink":"/tools/staticdocs/docs/guides/script-writing"}}'),r=n(7259),o=n(9796);let l={title:"Roles and Permissions",description:"Understanding COSMOS Enterprise roles and access control",sidebar_custom_props:{myEmoji:"\u{1F510}"}},t,d={},c=[{value:"Overview",id:"overview",level:2},{value:"Role Naming Convention",id:"role-naming-convention",level:3},{value:"Built-in Roles",id:"built-in-roles",level:2},{value:"Admin",id:"admin",level:3},{value:"Operator",id:"operator",level:3},{value:"Viewer",id:"viewer",level:3},{value:"Approver",id:"approver",level:3},{value:"Runner",id:"runner",level:3},{value:"Permission Definitions",id:"permission-definitions",level:2},{value:"System Permissions",id:"system-permissions",level:3},{value:"Telemetry Permissions",id:"telemetry-permissions",level:3},{value:"Command Permissions",id:"command-permissions",level:3},{value:"Script Permissions",id:"script-permissions",level:3},{value:"Administrative Permissions",id:"administrative-permissions",level:3},{value:"Approval Permissions",id:"approval-permissions",level:3},{value:"Command Authority",id:"command-authority",level:2},{value:"Custom Roles",id:"custom-roles",level:2},{value:"Creating Custom Roles",id:"creating-custom-roles",level:3},{value:"Custom Role Permissions",id:"custom-role-permissions",level:3},{value:"Authorization Flow",id:"authorization-flow",level:2},{value:"Default Users",id:"default-users",level:2},{value:"Best Practices",id:"best-practices",level:2},{value:"Managing Roles",id:"managing-roles",level:2},{value:"Viewing / Assigning Roles to Users",id:"viewing--assigning-roles-to-users",level:3}];function a(e){let s={a:"a",code:"code",h2:"h2",h3:"h3",img:"img",li:"li",ol:"ol",p:"p",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,o.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(s.p,{children:"COSMOS Enterprise provides a comprehensive role-based access control (RBAC) system that allows you to manage user permissions across different scopes. This system integrates with Keycloak for authentication and authorization."}),"\n",(0,r.jsx)(s.h2,{id:"overview",children:"Overview"}),"\n",(0,r.jsx)(s.p,{children:"Roles in COSMOS Enterprise control what actions users can perform within the system. Roles are assigned to users per scope, allowing fine-grained control over access to different missions or projects."}),"\n",(0,r.jsx)(s.h3,{id:"role-naming-convention",children:"Role Naming Convention"}),"\n",(0,r.jsxs)(s.p,{children:["Roles are assigned using the format: ",(0,r.jsx)(s.code,{children:"{SCOPE}__{ROLE_NAME}"})]}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"SCOPE"}),": The scope name (e.g., ",(0,r.jsx)(s.code,{children:"DEFAULT"}),") or ",(0,r.jsx)(s.code,{children:"ALLSCOPES"})," for global permissions"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"ROLE_NAME"}),": One of the built-in roles or a custom role name"]}),"\n"]}),"\n",(0,r.jsx)(s.p,{children:"Examples:"}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"DEFAULT__operator"})," - Operator role in the DEFAULT scope"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"MISSION1__viewer"})," - Viewer role in the MISSION1 scope"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"ALLSCOPES__admin"})," - Admin role across all scopes"]}),"\n"]}),"\n",(0,r.jsx)(s.h2,{id:"built-in-roles",children:"Built-in Roles"}),"\n",(0,r.jsx)(s.p,{children:"Individual built-in roles in COSMOS Enterprise are scoped to a minimal set of permissions. Individual users can have multiple roles (e.g., Admin and Operator) if users need administrative access and commanding access. COSMOS Enterprise includes five built-in roles with predefined permission sets:"}),"\n",(0,r.jsx)(s.h3,{id:"admin",children:"Admin"}),"\n",(0,r.jsxs)(s.p,{children:["The ",(0,r.jsx)(s.strong,{children:"Admin"})," role provides administrative access within a scope. Admins can also manage the files within the MinIO bucket."]}),"\n",(0,r.jsx)(s.p,{children:(0,r.jsx)(s.strong,{children:"Permissions:"})}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"system"})," - View system information"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"system_set"})," - Modify system settings"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"tlm"})," - View telemetry data"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"cmd_info"})," - View command information"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"script_view"})," - View scripts"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"admin"})," - Administrative functions (manage plugins, targets, interfaces, etc.)"]}),"\n"]}),"\n",(0,r.jsx)(s.p,{children:(0,r.jsx)(s.strong,{children:"Special Cases:"})}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:["When assigned to ",(0,r.jsx)(s.code,{children:"ALLSCOPES"}),", gains ",(0,r.jsx)(s.code,{children:"superadmin"})," permission for system-wide administration"]}),"\n",(0,r.jsx)(s.li,{children:"Can release command authority taken by other users in their scope"}),"\n"]}),"\n",(0,r.jsxs)(s.p,{children:[(0,r.jsx)(s.strong,{children:"Use Case:"})," Users responsible for system configuration and management."]}),"\n",(0,r.jsx)(s.h3,{id:"operator",children:"Operator"}),"\n",(0,r.jsxs)(s.p,{children:["The ",(0,r.jsx)(s.strong,{children:"Operator"})," role has full access except for administrative functions and approval rights."]}),"\n",(0,r.jsx)(s.p,{children:(0,r.jsx)(s.strong,{children:"Permissions:"})}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"system"})," - View system information"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"system_set"})," - Modify system settings"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"tlm"})," - View telemetry data"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"tlm_set"})," - Modify telemetry settings"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"cmd_info"})," - View command information"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"cmd_raw"})," - Send raw commands"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"cmd"})," - Send commands"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"script_view"})," - View scripts"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"script_edit"})," - Create and edit scripts"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"script_run"})," - Run scripts"]}),"\n"]}),"\n",(0,r.jsxs)(s.p,{children:[(0,r.jsx)(s.strong,{children:"Use Case:"})," Power users who need full operational control but not administrative access."]}),"\n",(0,r.jsx)(s.h3,{id:"viewer",children:"Viewer"}),"\n",(0,r.jsxs)(s.p,{children:["The ",(0,r.jsx)(s.strong,{children:"Viewer"})," role provides read-only access to the system."]}),"\n",(0,r.jsx)(s.p,{children:(0,r.jsx)(s.strong,{children:"Permissions:"})}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"system"})," - View system information"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"tlm"})," - View telemetry data"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"cmd_info"})," - View command information"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"script_view"})," - View scripts"]}),"\n"]}),"\n",(0,r.jsxs)(s.p,{children:[(0,r.jsx)(s.strong,{children:"Use Case:"})," Users who need to monitor telemetry and system status without making changes."]}),"\n",(0,r.jsx)(s.h3,{id:"approver",children:"Approver"}),"\n",(0,r.jsxs)(s.p,{children:["The ",(0,r.jsx)(s.strong,{children:"Approver"})," role is specifically for command approval workflows."]}),"\n",(0,r.jsx)(s.p,{children:(0,r.jsx)(s.strong,{children:"Permissions:"})}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"approve_hazardous"})," - Approve hazardous commands"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"approve_restricted"})," - Approve restricted commands"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"approve_normal"})," - Approve normal commands"]}),"\n"]}),"\n",(0,r.jsxs)(s.p,{children:[(0,r.jsx)(s.strong,{children:"Use Case:"})," Users responsible for reviewing and approving commands before execution."]}),"\n",(0,r.jsx)(s.h3,{id:"runner",children:"Runner"}),"\n",(0,r.jsxs)(s.p,{children:["The ",(0,r.jsx)(s.strong,{children:"Runner"})," role allows users to execute commands and scripts but cannot create or edit them. Runner does not come with approval rights."]}),"\n",(0,r.jsx)(s.p,{children:(0,r.jsx)(s.strong,{children:"Permissions:"})}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"system"})," - View system information"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"system_set"})," - Modify system settings"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"tlm"})," - View telemetry data"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"tlm_set"})," - Modify telemetry settings"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"cmd_info"})," - View command information"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"cmd_raw"})," - Send raw commands"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"cmd"})," - Send commands"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"script_view"})," - View scripts"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"script_run"})," - Run scripts"]}),"\n"]}),"\n",(0,r.jsxs)(s.p,{children:[(0,r.jsx)(s.strong,{children:"Use Case:"})," Operators who execute procedures and send commands but don't modify configurations or scripts."]}),"\n",(0,r.jsx)(s.h2,{id:"permission-definitions",children:"Permission Definitions"}),"\n",(0,r.jsx)(s.h3,{id:"system-permissions",children:"System Permissions"}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"system"})," - View system information and status"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"system_set"})," - Modify system settings and configurations"]}),"\n"]}),"\n",(0,r.jsx)(s.h3,{id:"telemetry-permissions",children:"Telemetry Permissions"}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"tlm"})," - View telemetry data"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"tlm_set"})," - Modify telemetry settings (limits, conversions, etc.)"]}),"\n"]}),"\n",(0,r.jsx)(s.h3,{id:"command-permissions",children:"Command Permissions"}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"cmd_info"})," - View command definitions and parameters"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"cmd_raw"})," - Send raw binary commands"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"cmd"})," - Send commands to targets"]}),"\n"]}),"\n",(0,r.jsx)(s.h3,{id:"script-permissions",children:"Script Permissions"}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"script_view"})," - View script contents"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"script_edit"})," - Create, edit, and delete scripts"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"script_run"})," - Execute scripts"]}),"\n"]}),"\n",(0,r.jsx)(s.h3,{id:"administrative-permissions",children:"Administrative Permissions"}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"admin"})," - Manage scope-level resources (targets, plugins, interfaces, routers, etc.)"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"superadmin"})," - System-wide administration across all scopes (requires ",(0,r.jsx)(s.code,{children:"ALLSCOPES__admin"}),")"]}),"\n"]}),"\n",(0,r.jsx)(s.h3,{id:"approval-permissions",children:"Approval Permissions"}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"approve_hazardous"})," - Approve hazardous commands"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"approve_restricted"})," - Approve restricted commands"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"approve_normal"})," - Approve normal commands"]}),"\n"]}),"\n",(0,r.jsx)(s.h2,{id:"command-authority",children:"Command Authority"}),"\n",(0,r.jsx)(s.p,{children:"When command authority is enabled for a scope, an additional layer of authorization is applied to command-related permissions:"}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsx)(s.li,{children:'Users must "take" command authority for a specific target before sending commands'}),"\n",(0,r.jsx)(s.li,{children:"Only the user who holds command authority can send commands to that target"}),"\n",(0,r.jsxs)(s.li,{children:["Admin users (with ",(0,r.jsx)(s.code,{children:"ALLSCOPES__admin"})," or ",(0,r.jsx)(s.code,{children:"{SCOPE}__admin"}),") can release authority taken by other users"]}),"\n",(0,r.jsxs)(s.li,{children:["Command authority applies to these permissions when executed manually:","\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsx)(s.li,{children:(0,r.jsx)(s.code,{children:"tlm_set"})}),"\n",(0,r.jsx)(s.li,{children:(0,r.jsx)(s.code,{children:"cmd_raw"})}),"\n",(0,r.jsx)(s.li,{children:(0,r.jsx)(s.code,{children:"cmd"})}),"\n",(0,r.jsx)(s.li,{children:(0,r.jsx)(s.code,{children:"script_run"})}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(s.h2,{id:"custom-roles",children:"Custom Roles"}),"\n",(0,r.jsx)(s.p,{children:"In addition to the built-in roles, you can create custom roles with specific permission combinations."}),"\n",(0,r.jsx)(s.h3,{id:"creating-custom-roles",children:"Creating Custom Roles"}),"\n",(0,r.jsx)(s.p,{children:"Custom roles are managed through the Admin Tool:"}),"\n",(0,r.jsxs)(s.ol,{children:["\n",(0,r.jsx)(s.li,{children:"Navigate to the Admin Tool"}),"\n",(0,r.jsx)(s.li,{children:"Go to the Roles tab"}),"\n",(0,r.jsx)(s.li,{children:'Click "Add" and enter a role name (single lowercase word recommended)'}),"\n",(0,r.jsx)(s.li,{children:'Click "Edit" to configure permissions for the role'}),"\n"]}),"\n",(0,r.jsx)(s.p,{children:(0,r.jsx)(s.img,{alt:"Add Role",src:n(4738).A+"",width:"2566",height:"860"})}),"\n",(0,r.jsx)(s.h3,{id:"custom-role-permissions",children:"Custom Role Permissions"}),"\n",(0,r.jsx)(s.p,{children:"Custom roles can have granular permissions that target specific resources:"}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"target_name"})," - Restrict permission to a specific target"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"packet_name"})," - Restrict permission to a specific packet"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"interface_name"})," - Restrict permission to a specific interface"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"router_name"})," - Restrict permission to a specific router"]}),"\n"]}),"\n",(0,r.jsxs)(s.p,{children:["Example: A custom role could allow ",(0,r.jsx)(s.code,{children:"cmd"})," permission only for the ",(0,r.jsx)(s.code,{children:"INST1"})," target."]}),"\n",(0,r.jsx)(s.p,{children:(0,r.jsx)(s.img,{alt:"Edit Role",src:n(6831).A+"",width:"1062",height:"1228"})}),"\n",(0,r.jsx)(s.h2,{id:"authorization-flow",children:"Authorization Flow"}),"\n",(0,r.jsx)(s.p,{children:"When a user attempts an action, COSMOS Enterprise performs the following checks:"}),"\n",(0,r.jsxs)(s.ol,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"Token Validation"})," - Verify the JWT token from Keycloak"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"Role Extraction"})," - Extract roles from the token's ",(0,r.jsx)(s.code,{children:"realm_access"})," claim"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"Scope Matching"})," - Match user roles against the requested scope or ",(0,r.jsx)(s.code,{children:"ALLSCOPES"})]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"Permission Check"})," - Verify the action's required permission is granted by the role"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"Resource Matching"})," - For custom roles, check if specific resources match"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"Command Authority"})," - If applicable, verify command authority for the target"]}),"\n"]}),"\n",(0,r.jsx)(s.h2,{id:"default-users",children:"Default Users"}),"\n",(0,r.jsx)(s.p,{children:"COSMOS Enterprise Keycloak realm includes default test users for each role:"}),"\n",(0,r.jsxs)(s.table,{children:[(0,r.jsx)(s.thead,{children:(0,r.jsxs)(s.tr,{children:[(0,r.jsx)(s.th,{children:"Username"}),(0,r.jsx)(s.th,{children:"Password"}),(0,r.jsx)(s.th,{children:"Default Role"}),(0,r.jsx)(s.th,{children:"Email"})]})}),(0,r.jsxs)(s.tbody,{children:[(0,r.jsxs)(s.tr,{children:[(0,r.jsx)(s.td,{children:"operator"}),(0,r.jsx)(s.td,{children:"operator"}),(0,r.jsx)(s.td,{children:"DEFAULT__operator"}),(0,r.jsx)(s.td,{children:(0,r.jsx)(s.a,{href:"mailto:operator@openc3.com",children:"operator@openc3.com"})})]}),(0,r.jsxs)(s.tr,{children:[(0,r.jsx)(s.td,{children:"runner"}),(0,r.jsx)(s.td,{children:"runner"}),(0,r.jsx)(s.td,{children:"DEFAULT__runner"}),(0,r.jsx)(s.td,{children:(0,r.jsx)(s.a,{href:"mailto:runner@openc3.com",children:"runner@openc3.com"})})]}),(0,r.jsxs)(s.tr,{children:[(0,r.jsx)(s.td,{children:"viewer"}),(0,r.jsx)(s.td,{children:"viewer"}),(0,r.jsx)(s.td,{children:"DEFAULT__viewer"}),(0,r.jsx)(s.td,{children:(0,r.jsx)(s.a,{href:"mailto:viewer@openc3.com",children:"viewer@openc3.com"})})]}),(0,r.jsxs)(s.tr,{children:[(0,r.jsx)(s.td,{children:"admin"}),(0,r.jsx)(s.td,{children:"admin"}),(0,r.jsx)(s.td,{children:"ALLSCOPES__admin"}),(0,r.jsx)(s.td,{children:(0,r.jsx)(s.a,{href:"mailto:admin@openc3.com",children:"admin@openc3.com"})})]}),(0,r.jsxs)(s.tr,{children:[(0,r.jsx)(s.td,{children:"approver"}),(0,r.jsx)(s.td,{children:"approver"}),(0,r.jsx)(s.td,{children:"DEFAULT__approver"}),(0,r.jsx)(s.td,{children:(0,r.jsx)(s.a,{href:"mailto:approver@openc3.com",children:"approver@openc3.com"})})]})]})]}),"\n",(0,r.jsxs)(s.p,{children:[(0,r.jsx)(s.strong,{children:"Note:"})," These are default development/testing accounts. In production deployments, you should configure proper authentication and remove or change these default credentials."]}),"\n",(0,r.jsx)(s.h2,{id:"best-practices",children:"Best Practices"}),"\n",(0,r.jsxs)(s.ol,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"Principle of Least Privilege"})," - Assign users the minimum permissions needed for their role"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"Use Scopes"})," - Leverage scopes to separate different missions or projects"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"Custom Roles"})," - Create custom roles for specialized needs rather than giving admin access"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"Command Authority"})," - Enable command authority for production systems to prevent conflicts"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"Regular Audits"})," - Review user roles and permissions periodically"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"Production Security"})," - Replace default credentials and integrate with your organization's SSO/IdP"]}),"\n"]}),"\n",(0,r.jsx)(s.h2,{id:"managing-roles",children:"Managing Roles"}),"\n",(0,r.jsx)(s.h3,{id:"viewing--assigning-roles-to-users",children:"Viewing / Assigning Roles to Users"}),"\n",(0,r.jsx)(s.p,{children:"Roles are managed in Keycloak:"}),"\n",(0,r.jsxs)(s.ol,{children:["\n",(0,r.jsx)(s.li,{children:"Access the Keycloak admin console"}),"\n",(0,r.jsx)(s.li,{children:"Navigate to Users"}),"\n",(0,r.jsx)(s.li,{children:"Select a user"}),"\n",(0,r.jsx)(s.li,{children:"Go to Role Mappings"}),"\n",(0,r.jsxs)(s.li,{children:["Assign roles using the ",(0,r.jsx)(s.code,{children:"{SCOPE}__{ROLE_NAME}"})," format"]}),"\n"]}),"\n",(0,r.jsx)(s.p,{children:(0,r.jsx)(s.img,{alt:"Keycloak User Roles",src:n(4945).A+"",width:"2980",height:"1354"})})]})}function h(e={}){let{wrapper:s}={...(0,o.R)(),...e.components};return s?(0,r.jsx)(s,{...e,children:(0,r.jsx)(a,{...e})}):a(e)}},4738:function(e,s,n){n.d(s,{A:()=>i});let i=n.p+"assets/images/add_role-e99225cd280a9de1e354586f00c92f52d0dae856ac015a561da2dd405de6cb55.png"},6831:function(e,s,n){n.d(s,{A:()=>i});let i=n.p+"assets/images/edit_role-1ea95cfab9edd9173196018fe14ec39ad0537e0c04c8f0f5af53fcf3173867df.png"},4945:function(e,s,n){n.d(s,{A:()=>i});let i=n.p+"assets/images/keycloak_user_roles-d4c78e2a5d33c4ea3016250d849b3363deccd21b9562561793b81981acf773fe.png"},9796:function(e,s,n){n.d(s,{R:()=>l,x:()=>t});var i=n(6363);let r={},o=i.createContext(r);function l(e){let s=i.useContext(o);return i.useMemo(function(){return"function"==typeof e?e(s):{...s,...e}},[s,e])}function t(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:l(e.components),i.createElement(o.Provider,{value:s},e.children)}}}]);
|
|
1
|
+
"use strict";(self.webpackChunkdocs_openc3_com=self.webpackChunkdocs_openc3_com||[]).push([["6490"],{9675:function(e,s,n){n.r(s),n.d(s,{metadata:()=>i,default:()=>h,frontMatter:()=>l,contentTitle:()=>t,toc:()=>c,assets:()=>d});var i=JSON.parse('{"id":"guides/roles-permissions","title":"Roles and Permissions","description":"Understanding COSMOS Enterprise roles and access control","source":"@site/docs/guides/roles-permissions.md","sourceDirName":"guides","slug":"/guides/roles-permissions","permalink":"/tools/staticdocs/docs/guides/roles-permissions","draft":false,"unlisted":false,"editUrl":"https://github.com/OpenC3/cosmos/tree/main/docs.openc3.com/docs/guides/roles-permissions.md","tags":[],"version":"current","frontMatter":{"title":"Roles and Permissions","description":"Understanding COSMOS Enterprise roles and access control","sidebar_custom_props":{"myEmoji":"\u{1F510}"}},"sidebar":"defaultSidebar","previous":{"title":"Reference Architectures","permalink":"/tools/staticdocs/docs/guides/reference-architectures"},"next":{"title":"Script Writing Guide","permalink":"/tools/staticdocs/docs/guides/script-writing"}}'),r=n(5656),o=n(5395);let l={title:"Roles and Permissions",description:"Understanding COSMOS Enterprise roles and access control",sidebar_custom_props:{myEmoji:"\u{1F510}"}},t,d={},c=[{value:"Overview",id:"overview",level:2},{value:"Role Naming Convention",id:"role-naming-convention",level:3},{value:"Built-in Roles",id:"built-in-roles",level:2},{value:"Admin",id:"admin",level:3},{value:"Operator",id:"operator",level:3},{value:"Viewer",id:"viewer",level:3},{value:"Approver",id:"approver",level:3},{value:"Runner",id:"runner",level:3},{value:"Permission Definitions",id:"permission-definitions",level:2},{value:"System Permissions",id:"system-permissions",level:3},{value:"Telemetry Permissions",id:"telemetry-permissions",level:3},{value:"Command Permissions",id:"command-permissions",level:3},{value:"Script Permissions",id:"script-permissions",level:3},{value:"Administrative Permissions",id:"administrative-permissions",level:3},{value:"Approval Permissions",id:"approval-permissions",level:3},{value:"Command Authority",id:"command-authority",level:2},{value:"Custom Roles",id:"custom-roles",level:2},{value:"Creating Custom Roles",id:"creating-custom-roles",level:3},{value:"Custom Role Permissions",id:"custom-role-permissions",level:3},{value:"Authorization Flow",id:"authorization-flow",level:2},{value:"Default Users",id:"default-users",level:2},{value:"Best Practices",id:"best-practices",level:2},{value:"Managing Roles",id:"managing-roles",level:2},{value:"Viewing / Assigning Roles to Users",id:"viewing--assigning-roles-to-users",level:3}];function a(e){let s={a:"a",code:"code",h2:"h2",h3:"h3",img:"img",li:"li",ol:"ol",p:"p",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,o.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(s.p,{children:"COSMOS Enterprise provides a comprehensive role-based access control (RBAC) system that allows you to manage user permissions across different scopes. This system integrates with Keycloak for authentication and authorization."}),"\n",(0,r.jsx)(s.h2,{id:"overview",children:"Overview"}),"\n",(0,r.jsx)(s.p,{children:"Roles in COSMOS Enterprise control what actions users can perform within the system. Roles are assigned to users per scope, allowing fine-grained control over access to different missions or projects."}),"\n",(0,r.jsx)(s.h3,{id:"role-naming-convention",children:"Role Naming Convention"}),"\n",(0,r.jsxs)(s.p,{children:["Roles are assigned using the format: ",(0,r.jsx)(s.code,{children:"{SCOPE}__{ROLE_NAME}"})]}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"SCOPE"}),": The scope name (e.g., ",(0,r.jsx)(s.code,{children:"DEFAULT"}),") or ",(0,r.jsx)(s.code,{children:"ALLSCOPES"})," for global permissions"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"ROLE_NAME"}),": One of the built-in roles or a custom role name"]}),"\n"]}),"\n",(0,r.jsx)(s.p,{children:"Examples:"}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"DEFAULT__operator"})," - Operator role in the DEFAULT scope"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"MISSION1__viewer"})," - Viewer role in the MISSION1 scope"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"ALLSCOPES__admin"})," - Admin role across all scopes"]}),"\n"]}),"\n",(0,r.jsx)(s.h2,{id:"built-in-roles",children:"Built-in Roles"}),"\n",(0,r.jsx)(s.p,{children:"Individual built-in roles in COSMOS Enterprise are scoped to a minimal set of permissions. Individual users can have multiple roles (e.g., Admin and Operator) if users need administrative access and commanding access. COSMOS Enterprise includes five built-in roles with predefined permission sets:"}),"\n",(0,r.jsx)(s.h3,{id:"admin",children:"Admin"}),"\n",(0,r.jsxs)(s.p,{children:["The ",(0,r.jsx)(s.strong,{children:"Admin"})," role provides administrative access within a scope. Admins can also manage the files within the MinIO bucket."]}),"\n",(0,r.jsx)(s.p,{children:(0,r.jsx)(s.strong,{children:"Permissions:"})}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"system"})," - View system information"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"system_set"})," - Modify system settings"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"tlm"})," - View telemetry data"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"cmd_info"})," - View command information"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"script_view"})," - View scripts"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"admin"})," - Administrative functions (manage plugins, targets, interfaces, etc.)"]}),"\n"]}),"\n",(0,r.jsx)(s.p,{children:(0,r.jsx)(s.strong,{children:"Special Cases:"})}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:["When assigned to ",(0,r.jsx)(s.code,{children:"ALLSCOPES"}),", gains ",(0,r.jsx)(s.code,{children:"superadmin"})," permission for system-wide administration"]}),"\n",(0,r.jsx)(s.li,{children:"Can release command authority taken by other users in their scope"}),"\n"]}),"\n",(0,r.jsxs)(s.p,{children:[(0,r.jsx)(s.strong,{children:"Use Case:"})," Users responsible for system configuration and management."]}),"\n",(0,r.jsx)(s.h3,{id:"operator",children:"Operator"}),"\n",(0,r.jsxs)(s.p,{children:["The ",(0,r.jsx)(s.strong,{children:"Operator"})," role has full access except for administrative functions and approval rights."]}),"\n",(0,r.jsx)(s.p,{children:(0,r.jsx)(s.strong,{children:"Permissions:"})}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"system"})," - View system information"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"system_set"})," - Modify system settings"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"tlm"})," - View telemetry data"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"tlm_set"})," - Modify telemetry settings"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"cmd_info"})," - View command information"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"cmd_raw"})," - Send raw commands"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"cmd"})," - Send commands"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"script_view"})," - View scripts"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"script_edit"})," - Create and edit scripts"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"script_run"})," - Run scripts"]}),"\n"]}),"\n",(0,r.jsxs)(s.p,{children:[(0,r.jsx)(s.strong,{children:"Use Case:"})," Power users who need full operational control but not administrative access."]}),"\n",(0,r.jsx)(s.h3,{id:"viewer",children:"Viewer"}),"\n",(0,r.jsxs)(s.p,{children:["The ",(0,r.jsx)(s.strong,{children:"Viewer"})," role provides read-only access to the system."]}),"\n",(0,r.jsx)(s.p,{children:(0,r.jsx)(s.strong,{children:"Permissions:"})}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"system"})," - View system information"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"tlm"})," - View telemetry data"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"cmd_info"})," - View command information"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"script_view"})," - View scripts"]}),"\n"]}),"\n",(0,r.jsxs)(s.p,{children:[(0,r.jsx)(s.strong,{children:"Use Case:"})," Users who need to monitor telemetry and system status without making changes."]}),"\n",(0,r.jsx)(s.h3,{id:"approver",children:"Approver"}),"\n",(0,r.jsxs)(s.p,{children:["The ",(0,r.jsx)(s.strong,{children:"Approver"})," role is specifically for command approval workflows."]}),"\n",(0,r.jsx)(s.p,{children:(0,r.jsx)(s.strong,{children:"Permissions:"})}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"approve_hazardous"})," - Approve hazardous commands"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"approve_restricted"})," - Approve restricted commands"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"approve_normal"})," - Approve normal commands"]}),"\n"]}),"\n",(0,r.jsxs)(s.p,{children:[(0,r.jsx)(s.strong,{children:"Use Case:"})," Users responsible for reviewing and approving commands before execution."]}),"\n",(0,r.jsx)(s.h3,{id:"runner",children:"Runner"}),"\n",(0,r.jsxs)(s.p,{children:["The ",(0,r.jsx)(s.strong,{children:"Runner"})," role allows users to execute commands and scripts but cannot create or edit them. Runner does not come with approval rights."]}),"\n",(0,r.jsx)(s.p,{children:(0,r.jsx)(s.strong,{children:"Permissions:"})}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"system"})," - View system information"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"system_set"})," - Modify system settings"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"tlm"})," - View telemetry data"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"tlm_set"})," - Modify telemetry settings"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"cmd_info"})," - View command information"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"cmd_raw"})," - Send raw commands"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"cmd"})," - Send commands"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"script_view"})," - View scripts"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"script_run"})," - Run scripts"]}),"\n"]}),"\n",(0,r.jsxs)(s.p,{children:[(0,r.jsx)(s.strong,{children:"Use Case:"})," Operators who execute procedures and send commands but don't modify configurations or scripts."]}),"\n",(0,r.jsx)(s.h2,{id:"permission-definitions",children:"Permission Definitions"}),"\n",(0,r.jsx)(s.h3,{id:"system-permissions",children:"System Permissions"}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"system"})," - View system information and status"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"system_set"})," - Modify system settings and configurations"]}),"\n"]}),"\n",(0,r.jsx)(s.h3,{id:"telemetry-permissions",children:"Telemetry Permissions"}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"tlm"})," - View telemetry data"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"tlm_set"})," - Modify telemetry settings (limits, conversions, etc.)"]}),"\n"]}),"\n",(0,r.jsx)(s.h3,{id:"command-permissions",children:"Command Permissions"}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"cmd_info"})," - View command definitions and parameters"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"cmd_raw"})," - Send raw binary commands"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"cmd"})," - Send commands to targets"]}),"\n"]}),"\n",(0,r.jsx)(s.h3,{id:"script-permissions",children:"Script Permissions"}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"script_view"})," - View script contents"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"script_edit"})," - Create, edit, and delete scripts"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"script_run"})," - Execute scripts"]}),"\n"]}),"\n",(0,r.jsx)(s.h3,{id:"administrative-permissions",children:"Administrative Permissions"}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"admin"})," - Manage scope-level resources (targets, plugins, interfaces, routers, etc.)"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"superadmin"})," - System-wide administration across all scopes (requires ",(0,r.jsx)(s.code,{children:"ALLSCOPES__admin"}),")"]}),"\n"]}),"\n",(0,r.jsx)(s.h3,{id:"approval-permissions",children:"Approval Permissions"}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"approve_hazardous"})," - Approve hazardous commands"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"approve_restricted"})," - Approve restricted commands"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"approve_normal"})," - Approve normal commands"]}),"\n"]}),"\n",(0,r.jsx)(s.h2,{id:"command-authority",children:"Command Authority"}),"\n",(0,r.jsx)(s.p,{children:"When command authority is enabled for a scope, an additional layer of authorization is applied to command-related permissions:"}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsx)(s.li,{children:'Users must "take" command authority for a specific target before sending commands'}),"\n",(0,r.jsx)(s.li,{children:"Only the user who holds command authority can send commands to that target"}),"\n",(0,r.jsxs)(s.li,{children:["Admin users (with ",(0,r.jsx)(s.code,{children:"ALLSCOPES__admin"})," or ",(0,r.jsx)(s.code,{children:"{SCOPE}__admin"}),") can release authority taken by other users"]}),"\n",(0,r.jsxs)(s.li,{children:["Command authority applies to these permissions when executed manually:","\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsx)(s.li,{children:(0,r.jsx)(s.code,{children:"tlm_set"})}),"\n",(0,r.jsx)(s.li,{children:(0,r.jsx)(s.code,{children:"cmd_raw"})}),"\n",(0,r.jsx)(s.li,{children:(0,r.jsx)(s.code,{children:"cmd"})}),"\n",(0,r.jsx)(s.li,{children:(0,r.jsx)(s.code,{children:"script_run"})}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(s.h2,{id:"custom-roles",children:"Custom Roles"}),"\n",(0,r.jsx)(s.p,{children:"In addition to the built-in roles, you can create custom roles with specific permission combinations."}),"\n",(0,r.jsx)(s.h3,{id:"creating-custom-roles",children:"Creating Custom Roles"}),"\n",(0,r.jsx)(s.p,{children:"Custom roles are managed through the Admin Tool:"}),"\n",(0,r.jsxs)(s.ol,{children:["\n",(0,r.jsx)(s.li,{children:"Navigate to the Admin Tool"}),"\n",(0,r.jsx)(s.li,{children:"Go to the Roles tab"}),"\n",(0,r.jsx)(s.li,{children:'Click "Add" and enter a role name (single lowercase word recommended)'}),"\n",(0,r.jsx)(s.li,{children:'Click "Edit" to configure permissions for the role'}),"\n"]}),"\n",(0,r.jsx)(s.p,{children:(0,r.jsx)(s.img,{alt:"Add Role",src:n(4738).A+"",width:"2566",height:"860"})}),"\n",(0,r.jsx)(s.h3,{id:"custom-role-permissions",children:"Custom Role Permissions"}),"\n",(0,r.jsx)(s.p,{children:"Custom roles can have granular permissions that target specific resources:"}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"target_name"})," - Restrict permission to a specific target"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"packet_name"})," - Restrict permission to a specific packet"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"interface_name"})," - Restrict permission to a specific interface"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"router_name"})," - Restrict permission to a specific router"]}),"\n"]}),"\n",(0,r.jsxs)(s.p,{children:["Example: A custom role could allow ",(0,r.jsx)(s.code,{children:"cmd"})," permission only for the ",(0,r.jsx)(s.code,{children:"INST1"})," target."]}),"\n",(0,r.jsx)(s.p,{children:(0,r.jsx)(s.img,{alt:"Edit Role",src:n(6831).A+"",width:"1062",height:"1228"})}),"\n",(0,r.jsx)(s.h2,{id:"authorization-flow",children:"Authorization Flow"}),"\n",(0,r.jsx)(s.p,{children:"When a user attempts an action, COSMOS Enterprise performs the following checks:"}),"\n",(0,r.jsxs)(s.ol,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"Token Validation"})," - Verify the JWT token from Keycloak"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"Role Extraction"})," - Extract roles from the token's ",(0,r.jsx)(s.code,{children:"realm_access"})," claim"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"Scope Matching"})," - Match user roles against the requested scope or ",(0,r.jsx)(s.code,{children:"ALLSCOPES"})]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"Permission Check"})," - Verify the action's required permission is granted by the role"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"Resource Matching"})," - For custom roles, check if specific resources match"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"Command Authority"})," - If applicable, verify command authority for the target"]}),"\n"]}),"\n",(0,r.jsx)(s.h2,{id:"default-users",children:"Default Users"}),"\n",(0,r.jsx)(s.p,{children:"COSMOS Enterprise Keycloak realm includes default test users for each role:"}),"\n",(0,r.jsxs)(s.table,{children:[(0,r.jsx)(s.thead,{children:(0,r.jsxs)(s.tr,{children:[(0,r.jsx)(s.th,{children:"Username"}),(0,r.jsx)(s.th,{children:"Password"}),(0,r.jsx)(s.th,{children:"Default Role"}),(0,r.jsx)(s.th,{children:"Email"})]})}),(0,r.jsxs)(s.tbody,{children:[(0,r.jsxs)(s.tr,{children:[(0,r.jsx)(s.td,{children:"operator"}),(0,r.jsx)(s.td,{children:"operator"}),(0,r.jsx)(s.td,{children:"DEFAULT__operator"}),(0,r.jsx)(s.td,{children:(0,r.jsx)(s.a,{href:"mailto:operator@openc3.com",children:"operator@openc3.com"})})]}),(0,r.jsxs)(s.tr,{children:[(0,r.jsx)(s.td,{children:"runner"}),(0,r.jsx)(s.td,{children:"runner"}),(0,r.jsx)(s.td,{children:"DEFAULT__runner"}),(0,r.jsx)(s.td,{children:(0,r.jsx)(s.a,{href:"mailto:runner@openc3.com",children:"runner@openc3.com"})})]}),(0,r.jsxs)(s.tr,{children:[(0,r.jsx)(s.td,{children:"viewer"}),(0,r.jsx)(s.td,{children:"viewer"}),(0,r.jsx)(s.td,{children:"DEFAULT__viewer"}),(0,r.jsx)(s.td,{children:(0,r.jsx)(s.a,{href:"mailto:viewer@openc3.com",children:"viewer@openc3.com"})})]}),(0,r.jsxs)(s.tr,{children:[(0,r.jsx)(s.td,{children:"admin"}),(0,r.jsx)(s.td,{children:"admin"}),(0,r.jsx)(s.td,{children:"ALLSCOPES__admin"}),(0,r.jsx)(s.td,{children:(0,r.jsx)(s.a,{href:"mailto:admin@openc3.com",children:"admin@openc3.com"})})]}),(0,r.jsxs)(s.tr,{children:[(0,r.jsx)(s.td,{children:"approver"}),(0,r.jsx)(s.td,{children:"approver"}),(0,r.jsx)(s.td,{children:"DEFAULT__approver"}),(0,r.jsx)(s.td,{children:(0,r.jsx)(s.a,{href:"mailto:approver@openc3.com",children:"approver@openc3.com"})})]})]})]}),"\n",(0,r.jsxs)(s.p,{children:[(0,r.jsx)(s.strong,{children:"Note:"})," These are default development/testing accounts. In production deployments, you should configure proper authentication and remove or change these default credentials."]}),"\n",(0,r.jsx)(s.h2,{id:"best-practices",children:"Best Practices"}),"\n",(0,r.jsxs)(s.ol,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"Principle of Least Privilege"})," - Assign users the minimum permissions needed for their role"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"Use Scopes"})," - Leverage scopes to separate different missions or projects"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"Custom Roles"})," - Create custom roles for specialized needs rather than giving admin access"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"Command Authority"})," - Enable command authority for production systems to prevent conflicts"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"Regular Audits"})," - Review user roles and permissions periodically"]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:"Production Security"})," - Replace default credentials and integrate with your organization's SSO/IdP"]}),"\n"]}),"\n",(0,r.jsx)(s.h2,{id:"managing-roles",children:"Managing Roles"}),"\n",(0,r.jsx)(s.h3,{id:"viewing--assigning-roles-to-users",children:"Viewing / Assigning Roles to Users"}),"\n",(0,r.jsx)(s.p,{children:"Roles are managed in Keycloak:"}),"\n",(0,r.jsxs)(s.ol,{children:["\n",(0,r.jsx)(s.li,{children:"Access the Keycloak admin console"}),"\n",(0,r.jsx)(s.li,{children:"Navigate to Users"}),"\n",(0,r.jsx)(s.li,{children:"Select a user"}),"\n",(0,r.jsx)(s.li,{children:"Go to Role Mappings"}),"\n",(0,r.jsxs)(s.li,{children:["Assign roles using the ",(0,r.jsx)(s.code,{children:"{SCOPE}__{ROLE_NAME}"})," format"]}),"\n"]}),"\n",(0,r.jsx)(s.p,{children:(0,r.jsx)(s.img,{alt:"Keycloak User Roles",src:n(4945).A+"",width:"2980",height:"1354"})})]})}function h(e={}){let{wrapper:s}={...(0,o.R)(),...e.components};return s?(0,r.jsx)(s,{...e,children:(0,r.jsx)(a,{...e})}):a(e)}},4738:function(e,s,n){n.d(s,{A:()=>i});let i=n.p+"assets/images/add_role-e99225cd280a9de1e354586f00c92f52d0dae856ac015a561da2dd405de6cb55.png"},6831:function(e,s,n){n.d(s,{A:()=>i});let i=n.p+"assets/images/edit_role-1ea95cfab9edd9173196018fe14ec39ad0537e0c04c8f0f5af53fcf3173867df.png"},4945:function(e,s,n){n.d(s,{A:()=>i});let i=n.p+"assets/images/keycloak_user_roles-d4c78e2a5d33c4ea3016250d849b3363deccd21b9562561793b81981acf773fe.png"},5395:function(e,s,n){n.d(s,{R:()=>l,x:()=>t});var i=n(7140);let r={},o=i.createContext(r);function l(e){let s=i.useContext(o);return i.useMemo(function(){return"function"==typeof e?e(s):{...s,...e}},[s,e])}function t(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:l(e.components),i.createElement(o.Provider,{value:s},e.children)}}}]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";(self.webpackChunkdocs_openc3_com=self.webpackChunkdocs_openc3_com||[]).push([["2553"],{9987:function(e,s,r){r.r(s),r.d(s,{metadata:()=>o,default:()=>h,frontMatter:()=>i,contentTitle:()=>c,toc:()=>l,assets:()=>a});var o=JSON.parse('{"id":"configuration/processors","title":"Processors","description":"Processors execute code every time a packet is received to calculate values","source":"@site/docs/configuration/processors.md","sourceDirName":"configuration","slug":"/configuration/processors","permalink":"/tools/staticdocs/docs/configuration/processors","draft":false,"unlisted":false,"editUrl":"https://github.com/OpenC3/cosmos/tree/main/docs.openc3.com/docs/configuration/processors.md","tags":[],"version":"current","sidebarPosition":10,"frontMatter":{"sidebar_position":10,"title":"Processors","description":"Processors execute code every time a packet is received to calculate values","sidebar_custom_props":{"myEmoji":"\u{1F9EE}"}},"sidebar":"defaultSidebar","previous":{"title":"Conversions","permalink":"/tools/staticdocs/docs/configuration/conversions"},"next":{"title":"Limits Response","permalink":"/tools/staticdocs/docs/configuration/limits-response"}}'),n=r(7259),t=r(9796);let i={sidebar_position:10,title:"Processors",description:"Processors execute code every time a packet is received to calculate values",sidebar_custom_props:{myEmoji:"\u{1F9EE}"}},c="Overview",a={},l=[{value:"Custom Processors",id:"custom-processors",level:2},{value:"<strong>init</strong>",id:"init",level:3},{value:"call",id:"call",level:3},{value:"reset",id:"reset",level:3},{value:"Instantiate Processor",id:"instantiate-processor",level:3},{value:"WATERMARK_PROCESSOR",id:"watermark_processor",level:2},{value:"STATISTICS_PROCESSOR",id:"statistics_processor",level:2}];function d(e){let s={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,t.R)(),...e.components},{TabItem:r,Tabs:o}=s;return r||p("TabItem",!0),o||p("Tabs",!0),(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(s.header,{children:(0,n.jsx)(s.h1,{id:"overview",children:"Overview"})}),"\n",(0,n.jsxs)(s.p,{children:["Processors execute code every time a packet is received to calculate values that can be retrieved by a ",(0,n.jsx)(s.a,{href:"/docs/configuration/conversions#processor_conversion",children:"ProcessorConversion"}),". Processors are applied using the ",(0,n.jsx)(s.a,{href:"/docs/configuration/telemetry#processor",children:"PROCESSOR"})," keyword and generate values unique to the processor."]}),"\n",(0,n.jsxs)(s.p,{children:["If you only want to perform calculations using a single packet to modify a telemetry value you probably want to use a ",(0,n.jsx)(s.a,{href:"/docs/configuration/conversions",children:"Conversion"}),". Processors are used when you're deriving a number of values from a single telemetry item."]}),"\n",(0,n.jsx)(s.h2,{id:"custom-processors",children:"Custom Processors"}),"\n",(0,n.jsxs)(s.p,{children:["You can easily create your own custom processors by using the ",(0,n.jsx)(s.a,{href:"/docs/getting-started/generators#processor-generator",children:"Processor Code Generator"}),". To generate a process you must be inside an existing COSMOS plugin. The generator takes both a target name and the processor name. For example if your plugin is called ",(0,n.jsx)(s.code,{children:"openc3-cosmos-gse"})," and you have an existing target named ",(0,n.jsx)(s.code,{children:"GSE"}),":"]}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-bash",children:"openc3-cosmos-gse % openc3.sh cli generate processor GSE slope --python\nProcessor targets/GSE/lib/slope_processor.py successfully generated!\nTo use the processor add the following to a telemetry packet:\n PROCESSOR SLOPE slope_processor.py <PARAMS...>\n"})}),"\n",(0,n.jsxs)(s.p,{children:["Note: To create a Ruby processor simply replace ",(0,n.jsx)(s.code,{children:"--python"})," with ",(0,n.jsx)(s.code,{children:"--ruby"}),"."]}),"\n",(0,n.jsxs)(s.p,{children:["The above command creates a processor called ",(0,n.jsx)(s.code,{children:"slope_processor.py"})," at ",(0,n.jsx)(s.code,{children:"targets/GSE/lib/slope_processor.py"}),". The code which is generated looks like the following:"]}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-python",children:"import math\nfrom openc3.processors.processor import Processor\n\n# Custom processor class\n# See https://docs.openc3.com/docs/configuration/processors\nclass SlopeProcessor(Processor):\n def __init__(self, item_name, num_samples, value_type='CONVERTED'):\n super().__init__(value_type)\n self.item_name = item_name.upper()\n self.num_samples = int(num_samples)\n self.reset()\n\n def call(self, value, packet, buffer):\n value = packet.read(self.item_name, self.value_type, buffer)\n # Don't process NaN or Infinite values\n if math.isnan(value) or math.isinf(value):\n return\n\n self.samples.append(value)\n if len(self.samples) > self.num_samples:\n self.samples = self.samples[-self.num_samples :]\n\n if len(self.samples) > 1:\n self.results['RATE_OF_CHANGE'] = (self.samples[-1] - self.samples[0]) / (len(self.samples) - 1)\n else:\n self.results['RATE_OF_CHANGE'] = None\n\n def reset(self):\n self.samples = []\n self.results['RATE_OF_CHANGE'] = None\n"})}),"\n",(0,n.jsx)(s.h3,{id:"init",children:(0,n.jsx)(s.strong,{children:"init"})}),"\n",(0,n.jsxs)(s.p,{children:["The ",(0,n.jsx)(s.strong,{children:"init"})," method is where the processor is initialized. The parameters specified are the parameters given in the configuration file when creating the processor. So for our example, the telemetry configuration file will look like:"]}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{children:"# Calculate the slope of TEMP1 over the last 60 samples (1 minute)\nPROCESSOR SLOPE slope_processor.py TEMP1 60\n"})}),"\n",(0,n.jsx)(s.h3,{id:"call",children:"call"}),"\n",(0,n.jsxs)(s.p,{children:["The call method is where the actual processor logic is implemented. In our case we want to calculate the rate of change from the first sample to the last sample. There are certainly more efficient ways to calculate a single rate of change value (you really only need 2 values) but this example shows how to keep a running list of values. Also note that if you're only performing a single calculation you might be better off using a ",(0,n.jsx)(s.a,{href:"/docs/configuration/conversions",children:"Conversion"}),"."]}),"\n",(0,n.jsx)(s.h3,{id:"reset",children:"reset"}),"\n",(0,n.jsxs)(s.p,{children:["The reset method initializes the samples and clears any state by setting the results to ",(0,n.jsx)(s.code,{children:"None"}),"."]}),"\n",(0,n.jsx)(s.h3,{id:"instantiate-processor",children:"Instantiate Processor"}),"\n",(0,n.jsxs)(s.p,{children:["Now that we have implemented the processor logic we need to create the processor by adding it to a telemetry packet with the line ",(0,n.jsx)(s.code,{children:"PROCESSOR SLOPE slope_processor.py"})," in the ",(0,n.jsx)(s.a,{href:"/docs/configuration/telemetry",children:"telemetry"})," definition file. We also need a ",(0,n.jsx)(s.a,{href:"/docs/configuration/conversions#processor_conversion",children:"ProcessorConversion"})," to pull the calculated values out of the processor and into a ",(0,n.jsx)(s.a,{href:"/docs/configuration/telemetry#derived-items",children:"derived"})," telemetry item. This could look something like this:"]}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-bash",children:'TELEMETRY GSE DATA BIG_ENDIAN "Data packet"\n ... # Telemetry items\n ITEM TEMP1SLOPE 0 0 DERIVED "Rate of change for the last 60 samples of TEMP1"\n READ_CONVERSION openc3/conversions/processor_conversion.py SLOPE RATE_OF_CHANGE\n # Calculate the slope of TEMP1 over the last 60 samples (1 minute)\n PROCESSOR SLOPE slope_processor.py TEMP1 60\n'})}),"\n",(0,n.jsx)(s.p,{children:"If you have multiple values you're calculating you simply add additional ITEMs with READ_COVERSIONs and read the various values the processor calculates in the results."}),"\n",(0,n.jsx)(s.h1,{id:"built-in-processors",children:"Built-in Processors"}),"\n",(0,n.jsx)(s.h2,{id:"watermark_processor",children:"WATERMARK_PROCESSOR"}),"\n",(0,n.jsx)(s.p,{children:(0,n.jsx)(s.strong,{children:"Calculates high and low values for a given item"})}),"\n",(0,n.jsxs)(s.p,{children:["Stores high and low values for a given item as HIGH_WATER and LOW_WATER.\nValues are retrieved using a ",(0,n.jsx)(s.a,{href:"/docs/configuration/conversions#processor_conversion",children:"ProcessorConversion"}),"."]}),"\n",(0,n.jsxs)(s.table,{children:[(0,n.jsx)(s.thead,{children:(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.th,{children:"Parameter"}),(0,n.jsx)(s.th,{children:"Description"}),(0,n.jsx)(s.th,{children:"Required"})]})}),(0,n.jsxs)(s.tbody,{children:[(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Item Name"}),(0,n.jsx)(s.td,{children:"The item name to calculate high and low values for"}),(0,n.jsx)(s.td,{children:"True"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Value Type"}),(0,n.jsxs)(s.td,{children:["The type of the value to display. Default is CONVERTED.",(0,n.jsx)("br",{}),(0,n.jsx)("br",{}),"Valid Values: ",(0,n.jsx)("span",{class:"values",children:"RAW, CONVERTED"})]}),(0,n.jsx)(s.td,{children:"False"})]})]})]}),"\n",(0,n.jsxs)(o,{groupId:"script-language",children:[(0,n.jsx)(r,{value:"python",label:"Python",children:(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-python",children:'PROCESSOR TEMP1WATER openc3/conversions/watermark_processor.py TEMP1\nITEM TEMP1HIGH 0 0 DERIVED "High-water mark for TEMP1"\n READ_CONVERSION openc3/conversions/processor_conversion.py TEMP1WATER HIGH_WATER\n'})})}),(0,n.jsx)(r,{value:"ruby",label:"Ruby",children:(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-ruby",children:'PROCESSOR TEMP1WATER watermark_processor.rb TEMP1\nITEM TEMP1HIGH 0 0 DERIVED "High-water mark for TEMP1"\n READ_CONVERSION processor_conversion.rb TEMP1WATER HIGH_WATER\n'})})})]}),"\n",(0,n.jsx)(s.h2,{id:"statistics_processor",children:"STATISTICS_PROCESSOR"}),"\n",(0,n.jsx)(s.p,{children:(0,n.jsx)(s.strong,{children:"Calculates statistics for a given item"})}),"\n",(0,n.jsxs)(s.p,{children:["This processor calculates statistics for a given item as MIN, MAX, MEAN, and STDDEV\nover a specified number of samples. Values are retrieved using a ",(0,n.jsx)(s.a,{href:"/docs/configuration/conversions#processor_conversion",children:"ProcessorConversion"}),"."]}),"\n",(0,n.jsxs)(s.table,{children:[(0,n.jsx)(s.thead,{children:(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.th,{children:"Parameter"}),(0,n.jsx)(s.th,{children:"Description"}),(0,n.jsx)(s.th,{children:"Required"})]})}),(0,n.jsxs)(s.tbody,{children:[(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Item Name"}),(0,n.jsx)(s.td,{children:"The item name to calculate statistics for"}),(0,n.jsx)(s.td,{children:"True"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Samples to Average"}),(0,n.jsx)(s.td,{children:"The number of samples to average for statistics"}),(0,n.jsx)(s.td,{children:"True"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Value Type"}),(0,n.jsxs)(s.td,{children:["The type of the value to display. Default is CONVERTED.",(0,n.jsx)("br",{}),(0,n.jsx)("br",{}),"Valid Values: ",(0,n.jsx)("span",{class:"values",children:"RAW, CONVERTED"})]}),(0,n.jsx)(s.td,{children:"False"})]})]})]}),"\n",(0,n.jsxs)(o,{groupId:"script-language",children:[(0,n.jsx)(r,{value:"python",label:"Python",children:(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-python",children:'PROCESSOR TEMP1STAT openc3/conversions/statistics_processor.py TEMP1 100\nITEM TEMP1STDDEV 0 0 DERIVED "Stddev of most recent 100 samples for TEMP1"\n READ_CONVERSION openc3/conversions/processor_conversion.py TEMP1STAT STDDEV FLOAT 64\n'})})}),(0,n.jsx)(r,{value:"ruby",label:"Ruby",children:(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-ruby",children:'PROCESSOR TEMP1STAT statistics_processor.rb TEMP1 100\nITEM TEMP1STDDEV 0 0 DERIVED "Stddev of most recent 100 samples for TEMP1"\n READ_CONVERSION processor_conversion.rb TEMP1STAT STDDEV FLOAT 64\n'})})})]})]})}function h(e={}){let{wrapper:s}={...(0,t.R)(),...e.components};return s?(0,n.jsx)(s,{...e,children:(0,n.jsx)(d,{...e})}):d(e)}function p(e,s){throw Error("Expected "+(s?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}},9796:function(e,s,r){r.d(s,{R:()=>i,x:()=>c});var o=r(6363);let n={},t=o.createContext(n);function i(e){let s=o.useContext(t);return o.useMemo(function(){return"function"==typeof e?e(s):{...s,...e}},[s,e])}function c(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:i(e.components),o.createElement(t.Provider,{value:s},e.children)}}}]);
|
|
1
|
+
"use strict";(self.webpackChunkdocs_openc3_com=self.webpackChunkdocs_openc3_com||[]).push([["2553"],{1048:function(e,s,r){r.r(s),r.d(s,{metadata:()=>o,default:()=>h,frontMatter:()=>i,contentTitle:()=>c,toc:()=>l,assets:()=>a});var o=JSON.parse('{"id":"configuration/processors","title":"Processors","description":"Processors execute code every time a packet is received to calculate values","source":"@site/docs/configuration/processors.md","sourceDirName":"configuration","slug":"/configuration/processors","permalink":"/tools/staticdocs/docs/configuration/processors","draft":false,"unlisted":false,"editUrl":"https://github.com/OpenC3/cosmos/tree/main/docs.openc3.com/docs/configuration/processors.md","tags":[],"version":"current","sidebarPosition":10,"frontMatter":{"sidebar_position":10,"title":"Processors","description":"Processors execute code every time a packet is received to calculate values","sidebar_custom_props":{"myEmoji":"\u{1F9EE}"}},"sidebar":"defaultSidebar","previous":{"title":"Conversions","permalink":"/tools/staticdocs/docs/configuration/conversions"},"next":{"title":"Limits Response","permalink":"/tools/staticdocs/docs/configuration/limits-response"}}'),n=r(5656),t=r(5395);let i={sidebar_position:10,title:"Processors",description:"Processors execute code every time a packet is received to calculate values",sidebar_custom_props:{myEmoji:"\u{1F9EE}"}},c="Overview",a={},l=[{value:"Custom Processors",id:"custom-processors",level:2},{value:"<strong>init</strong>",id:"init",level:3},{value:"call",id:"call",level:3},{value:"reset",id:"reset",level:3},{value:"Instantiate Processor",id:"instantiate-processor",level:3},{value:"WATERMARK_PROCESSOR",id:"watermark_processor",level:2},{value:"STATISTICS_PROCESSOR",id:"statistics_processor",level:2}];function d(e){let s={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,t.R)(),...e.components},{TabItem:r,Tabs:o}=s;return r||p("TabItem",!0),o||p("Tabs",!0),(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(s.header,{children:(0,n.jsx)(s.h1,{id:"overview",children:"Overview"})}),"\n",(0,n.jsxs)(s.p,{children:["Processors execute code every time a packet is received to calculate values that can be retrieved by a ",(0,n.jsx)(s.a,{href:"/docs/configuration/conversions#processor_conversion",children:"ProcessorConversion"}),". Processors are applied using the ",(0,n.jsx)(s.a,{href:"/docs/configuration/telemetry#processor",children:"PROCESSOR"})," keyword and generate values unique to the processor."]}),"\n",(0,n.jsxs)(s.p,{children:["If you only want to perform calculations using a single packet to modify a telemetry value you probably want to use a ",(0,n.jsx)(s.a,{href:"/docs/configuration/conversions",children:"Conversion"}),". Processors are used when you're deriving a number of values from a single telemetry item."]}),"\n",(0,n.jsx)(s.h2,{id:"custom-processors",children:"Custom Processors"}),"\n",(0,n.jsxs)(s.p,{children:["You can easily create your own custom processors by using the ",(0,n.jsx)(s.a,{href:"/docs/getting-started/generators#processor-generator",children:"Processor Code Generator"}),". To generate a process you must be inside an existing COSMOS plugin. The generator takes both a target name and the processor name. For example if your plugin is called ",(0,n.jsx)(s.code,{children:"openc3-cosmos-gse"})," and you have an existing target named ",(0,n.jsx)(s.code,{children:"GSE"}),":"]}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-bash",children:"openc3-cosmos-gse % openc3.sh cli generate processor GSE slope --python\nProcessor targets/GSE/lib/slope_processor.py successfully generated!\nTo use the processor add the following to a telemetry packet:\n PROCESSOR SLOPE slope_processor.py <PARAMS...>\n"})}),"\n",(0,n.jsxs)(s.p,{children:["Note: To create a Ruby processor simply replace ",(0,n.jsx)(s.code,{children:"--python"})," with ",(0,n.jsx)(s.code,{children:"--ruby"}),"."]}),"\n",(0,n.jsxs)(s.p,{children:["The above command creates a processor called ",(0,n.jsx)(s.code,{children:"slope_processor.py"})," at ",(0,n.jsx)(s.code,{children:"targets/GSE/lib/slope_processor.py"}),". The code which is generated looks like the following:"]}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-python",children:"import math\nfrom openc3.processors.processor import Processor\n\n# Custom processor class\n# See https://docs.openc3.com/docs/configuration/processors\nclass SlopeProcessor(Processor):\n def __init__(self, item_name, num_samples, value_type='CONVERTED'):\n super().__init__(value_type)\n self.item_name = item_name.upper()\n self.num_samples = int(num_samples)\n self.reset()\n\n def call(self, value, packet, buffer):\n value = packet.read(self.item_name, self.value_type, buffer)\n # Don't process NaN or Infinite values\n if math.isnan(value) or math.isinf(value):\n return\n\n self.samples.append(value)\n if len(self.samples) > self.num_samples:\n self.samples = self.samples[-self.num_samples :]\n\n if len(self.samples) > 1:\n self.results['RATE_OF_CHANGE'] = (self.samples[-1] - self.samples[0]) / (len(self.samples) - 1)\n else:\n self.results['RATE_OF_CHANGE'] = None\n\n def reset(self):\n self.samples = []\n self.results['RATE_OF_CHANGE'] = None\n"})}),"\n",(0,n.jsx)(s.h3,{id:"init",children:(0,n.jsx)(s.strong,{children:"init"})}),"\n",(0,n.jsxs)(s.p,{children:["The ",(0,n.jsx)(s.strong,{children:"init"})," method is where the processor is initialized. The parameters specified are the parameters given in the configuration file when creating the processor. So for our example, the telemetry configuration file will look like:"]}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{children:"# Calculate the slope of TEMP1 over the last 60 samples (1 minute)\nPROCESSOR SLOPE slope_processor.py TEMP1 60\n"})}),"\n",(0,n.jsx)(s.h3,{id:"call",children:"call"}),"\n",(0,n.jsxs)(s.p,{children:["The call method is where the actual processor logic is implemented. In our case we want to calculate the rate of change from the first sample to the last sample. There are certainly more efficient ways to calculate a single rate of change value (you really only need 2 values) but this example shows how to keep a running list of values. Also note that if you're only performing a single calculation you might be better off using a ",(0,n.jsx)(s.a,{href:"/docs/configuration/conversions",children:"Conversion"}),"."]}),"\n",(0,n.jsx)(s.h3,{id:"reset",children:"reset"}),"\n",(0,n.jsxs)(s.p,{children:["The reset method initializes the samples and clears any state by setting the results to ",(0,n.jsx)(s.code,{children:"None"}),"."]}),"\n",(0,n.jsx)(s.h3,{id:"instantiate-processor",children:"Instantiate Processor"}),"\n",(0,n.jsxs)(s.p,{children:["Now that we have implemented the processor logic we need to create the processor by adding it to a telemetry packet with the line ",(0,n.jsx)(s.code,{children:"PROCESSOR SLOPE slope_processor.py"})," in the ",(0,n.jsx)(s.a,{href:"/docs/configuration/telemetry",children:"telemetry"})," definition file. We also need a ",(0,n.jsx)(s.a,{href:"/docs/configuration/conversions#processor_conversion",children:"ProcessorConversion"})," to pull the calculated values out of the processor and into a ",(0,n.jsx)(s.a,{href:"/docs/configuration/telemetry#derived-items",children:"derived"})," telemetry item. This could look something like this:"]}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-bash",children:'TELEMETRY GSE DATA BIG_ENDIAN "Data packet"\n ... # Telemetry items\n ITEM TEMP1SLOPE 0 0 DERIVED "Rate of change for the last 60 samples of TEMP1"\n READ_CONVERSION openc3/conversions/processor_conversion.py SLOPE RATE_OF_CHANGE\n # Calculate the slope of TEMP1 over the last 60 samples (1 minute)\n PROCESSOR SLOPE slope_processor.py TEMP1 60\n'})}),"\n",(0,n.jsx)(s.p,{children:"If you have multiple values you're calculating you simply add additional ITEMs with READ_COVERSIONs and read the various values the processor calculates in the results."}),"\n",(0,n.jsx)(s.h1,{id:"built-in-processors",children:"Built-in Processors"}),"\n",(0,n.jsx)(s.h2,{id:"watermark_processor",children:"WATERMARK_PROCESSOR"}),"\n",(0,n.jsx)(s.p,{children:(0,n.jsx)(s.strong,{children:"Calculates high and low values for a given item"})}),"\n",(0,n.jsxs)(s.p,{children:["Stores high and low values for a given item as HIGH_WATER and LOW_WATER.\nValues are retrieved using a ",(0,n.jsx)(s.a,{href:"/docs/configuration/conversions#processor_conversion",children:"ProcessorConversion"}),"."]}),"\n",(0,n.jsxs)(s.table,{children:[(0,n.jsx)(s.thead,{children:(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.th,{children:"Parameter"}),(0,n.jsx)(s.th,{children:"Description"}),(0,n.jsx)(s.th,{children:"Required"})]})}),(0,n.jsxs)(s.tbody,{children:[(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Item Name"}),(0,n.jsx)(s.td,{children:"The item name to calculate high and low values for"}),(0,n.jsx)(s.td,{children:"True"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Value Type"}),(0,n.jsxs)(s.td,{children:["The type of the value to display. Default is CONVERTED.",(0,n.jsx)("br",{}),(0,n.jsx)("br",{}),"Valid Values: ",(0,n.jsx)("span",{class:"values",children:"RAW, CONVERTED"})]}),(0,n.jsx)(s.td,{children:"False"})]})]})]}),"\n",(0,n.jsxs)(o,{groupId:"script-language",children:[(0,n.jsx)(r,{value:"python",label:"Python",children:(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-python",children:'PROCESSOR TEMP1WATER openc3/conversions/watermark_processor.py TEMP1\nITEM TEMP1HIGH 0 0 DERIVED "High-water mark for TEMP1"\n READ_CONVERSION openc3/conversions/processor_conversion.py TEMP1WATER HIGH_WATER\n'})})}),(0,n.jsx)(r,{value:"ruby",label:"Ruby",children:(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-ruby",children:'PROCESSOR TEMP1WATER watermark_processor.rb TEMP1\nITEM TEMP1HIGH 0 0 DERIVED "High-water mark for TEMP1"\n READ_CONVERSION processor_conversion.rb TEMP1WATER HIGH_WATER\n'})})})]}),"\n",(0,n.jsx)(s.h2,{id:"statistics_processor",children:"STATISTICS_PROCESSOR"}),"\n",(0,n.jsx)(s.p,{children:(0,n.jsx)(s.strong,{children:"Calculates statistics for a given item"})}),"\n",(0,n.jsxs)(s.p,{children:["This processor calculates statistics for a given item as MIN, MAX, MEAN, and STDDEV\nover a specified number of samples. Values are retrieved using a ",(0,n.jsx)(s.a,{href:"/docs/configuration/conversions#processor_conversion",children:"ProcessorConversion"}),"."]}),"\n",(0,n.jsxs)(s.table,{children:[(0,n.jsx)(s.thead,{children:(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.th,{children:"Parameter"}),(0,n.jsx)(s.th,{children:"Description"}),(0,n.jsx)(s.th,{children:"Required"})]})}),(0,n.jsxs)(s.tbody,{children:[(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Item Name"}),(0,n.jsx)(s.td,{children:"The item name to calculate statistics for"}),(0,n.jsx)(s.td,{children:"True"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Samples to Average"}),(0,n.jsx)(s.td,{children:"The number of samples to average for statistics"}),(0,n.jsx)(s.td,{children:"True"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Value Type"}),(0,n.jsxs)(s.td,{children:["The type of the value to display. Default is CONVERTED.",(0,n.jsx)("br",{}),(0,n.jsx)("br",{}),"Valid Values: ",(0,n.jsx)("span",{class:"values",children:"RAW, CONVERTED"})]}),(0,n.jsx)(s.td,{children:"False"})]})]})]}),"\n",(0,n.jsxs)(o,{groupId:"script-language",children:[(0,n.jsx)(r,{value:"python",label:"Python",children:(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-python",children:'PROCESSOR TEMP1STAT openc3/conversions/statistics_processor.py TEMP1 100\nITEM TEMP1STDDEV 0 0 DERIVED "Stddev of most recent 100 samples for TEMP1"\n READ_CONVERSION openc3/conversions/processor_conversion.py TEMP1STAT STDDEV FLOAT 64\n'})})}),(0,n.jsx)(r,{value:"ruby",label:"Ruby",children:(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-ruby",children:'PROCESSOR TEMP1STAT statistics_processor.rb TEMP1 100\nITEM TEMP1STDDEV 0 0 DERIVED "Stddev of most recent 100 samples for TEMP1"\n READ_CONVERSION processor_conversion.rb TEMP1STAT STDDEV FLOAT 64\n'})})})]})]})}function h(e={}){let{wrapper:s}={...(0,t.R)(),...e.components};return s?(0,n.jsx)(s,{...e,children:(0,n.jsx)(d,{...e})}):d(e)}function p(e,s){throw Error("Expected "+(s?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}},5395:function(e,s,r){r.d(s,{R:()=>i,x:()=>c});var o=r(7140);let n={},t=o.createContext(n);function i(e){let s=o.useContext(t);return o.useMemo(function(){return"function"==typeof e?e(s):{...s,...e}},[s,e])}function c(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:i(e.components),o.createElement(t.Provider,{value:s},e.children)}}}]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";(self.webpackChunkdocs_openc3_com=self.webpackChunkdocs_openc3_com||[]).push([["4189"],{5795:function(e,n,s){s.r(n),s.d(n,{metadata:()=>o,default:()=>d,frontMatter:()=>l,contentTitle:()=>r,toc:()=>c,assets:()=>a});var o=JSON.parse('{"id":"meta/licenses","title":"Licenses","description":"COSMOS licenses including the AGPLv3 vs Commercial","source":"@site/docs/meta/licenses.md","sourceDirName":"meta","slug":"/meta/licenses","permalink":"/tools/staticdocs/docs/meta/licenses","draft":false,"unlisted":false,"editUrl":"https://github.com/OpenC3/cosmos/tree/main/docs.openc3.com/docs/meta/licenses.md","tags":[],"version":"current","frontMatter":{"title":"Licenses","description":"COSMOS licenses including the AGPLv3 vs Commercial","sidebar_custom_props":{"myEmoji":"\u{1F575}\uFE0F"}},"sidebar":"defaultSidebar","previous":{"title":"Contributing","permalink":"/tools/staticdocs/docs/meta/contributing"},"next":{"title":"Philosophy","permalink":"/tools/staticdocs/docs/meta/philosophy"}}'),i=s(7259),t=s(9796);let l={title:"Licenses",description:"COSMOS licenses including the AGPLv3 vs Commercial",sidebar_custom_props:{myEmoji:"\u{1F575}\uFE0F"}},r,a={},c=[{value:"AGPLv3",id:"agplv3",level:2},{value:"Evaluation and Education Use Only",id:"evaluation-and-education-use-only",level:2},{value:"Commercial License",id:"commercial-license",level:2},{value:"Why you should buy a Commercial License",id:"why-you-should-buy-a-commercial-license",level:3},{value:"FAQs",id:"faqs",level:2}];function h(e){let n={a:"a",code:"code",em:"em",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,t.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.p,{children:"OpenC3 COSMOS is offered under a tri-licensing model allowing users to choose between the following three options:"}),"\n",(0,i.jsx)(n.h2,{id:"agplv3",children:"AGPLv3"}),"\n",(0,i.jsxs)(n.p,{children:["This is our default open source license and the license that most free users use. The AGPLv3 is a modification of the GPLv3 which is what is known as a copy-left license or a viral license. You can read the whole thing here: ",(0,i.jsx)(n.a,{href:"https://github.com/OpenC3/cosmos/blob/main/LICENSE.txt",children:"OpenC3 AGPLv3"})]}),"\n",(0,i.jsx)(n.p,{children:"Obviously, the actual license text applies, but here is a short summary:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"The AGPL allows users to use the code however they want: For business, personal, etc., as long as they follow the other terms:"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Users are anyone who could access the web-app. On the public internet, that is the whole world. On a private network, it is anyone with access to that network."}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"The software is provided as-is, no warranty"}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Users must be given access to all the source code and are also allowed to use it however they want under the same terms of the AGPLv3. This includes any modifications made, anything added, and all plugins."}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"For web applications (like COSMOS), a link must be provided to all of the source code."}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"There are some key implications of the above:"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"You cannot keep anything proprietary from your users. They have the rights to take the code (and configuration) and do anything they want with it. You CANNOT impede these rights or you are violating the AGPLv3 and YOU lose the rights to use our software."}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"You must provide a digital link to all source code for your users, including plugins."}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"All plugins must be licensed in an AGPLv3 compatible fashion. We recommend the MIT license because that allows your plugins to be compatible with the AGPLv3 and our commercial license. You can also use a dual license similar to what we do indicating the AGPLv3 or a purchased OpenC3 Commercial license."}),"\n"]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"The AGPLv3 license is often chosen because it works well for open core products like COSMOS. Competitors cannot take the open source product and license it under different terms. They would be forever locked into the AGPLv3 which is difficult to monetize, because your customers can take any code you provide and publish it on the internet for free use by everyone."}),"\n",(0,i.jsx)(n.p,{children:"As the copyright holder, OpenC3 is able to license the product and derivatives commercially. No-one else can do this. (OpenC3 is also able to license legacy Ball Aerospace COSMOS code under IP agreement)"}),"\n",(0,i.jsx)(n.h2,{id:"evaluation-and-education-use-only",children:"Evaluation and Education Use Only"}),"\n",(0,i.jsxs)(n.p,{children:["This license takes effect as soon as you use any plugin we publish under Evaluation and Education terms. Currently the only plugin we use for this is our CCSDS CFDP plugin: ",(0,i.jsx)(n.a,{href:"https://github.com/OpenC3/openc3-cosmos-cfdp",children:"CFDP Plugin"})]}),"\n",(0,i.jsx)(n.p,{children:"You can read the whole license here:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:'# OpenC3 Evaluation and Educational License\n#\n# Copyright 2023 OpenC3, Inc.\n#\n# This work is licensed for evaluation and educational purposes only.\n# It may NOT be used for formal development, integration and test, operations\n# or any other commercial purpose without the purchase of a commercial license\n# from OpenC3, Inc.\n#\n# The above copyright notice and this permission notice shall be included in all copies\n# or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\n# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n'})}),"\n",(0,i.jsx)(n.p,{children:"This license is pretty straight forward, but the key is you can't use this code for any real work leading to a product (Formal Development, Integration and Test, or Operations) unless you switch to purchasing a commercial license."}),"\n",(0,i.jsx)(n.h2,{id:"commercial-license",children:"Commercial License"}),"\n",(0,i.jsx)(n.p,{children:"This license is a signed contract with OpenC3. It allows use of our code for a program under contractual terms where you do not have to follow the AGPLv3."}),"\n",(0,i.jsx)(n.p,{children:"Generally we license to a specific project with terms that allow for unlimited users, and installs as needed by that project. Any code and plugins that you develop under the commercial license can be kept proprietary."}),"\n",(0,i.jsx)(n.p,{children:"These licenses are sold as yearly subscriptions, or as a non-expiring perpetual license. We also offer site licenses, and licenses to support unlimited missions on a government framework architecture."}),"\n",(0,i.jsx)(n.p,{children:"Of course with our commercial license, you also get all the extra functionality of our Enterprise product."}),"\n",(0,i.jsx)(n.h3,{id:"why-you-should-buy-a-commercial-license",children:"Why you should buy a Commercial License"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"You want to save years and tens of millions of dollars developing the same functionality yourself."}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"You want all of the Enterprise functionality of COSMOS Enterprise"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsx)(n.li,{children:"User Accounts"}),"\n",(0,i.jsx)(n.li,{children:"Role Based Access Control"}),"\n",(0,i.jsx)(n.li,{children:"LDAP Support"}),"\n",(0,i.jsx)(n.li,{children:"Kubernetes Support"}),"\n",(0,i.jsx)(n.li,{children:"Cloud Deployment Configurations"}),"\n",(0,i.jsx)(n.li,{children:"The right to use CFDP and other Enterprise Only plugins"}),"\n",(0,i.jsx)(n.li,{children:"Grafana Support"}),"\n",(0,i.jsx)(n.li,{children:"Support from the COSMOS Developers"}),"\n",(0,i.jsxs)(n.li,{children:["Lots more - See our ",(0,i.jsx)(n.a,{href:"https://openc3.com/enterprise",children:"Enterprise"})," page"]}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"You don't want to follow the AGPLv3"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsx)(n.li,{children:"You want to keep the code and plugins you develop proprietary"}),"\n",(0,i.jsx)(n.li,{children:"You don't want to publish an accessible link to your source code"}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"You want to support the continued development and innovation of the COSMOS product"}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.em,{children:"We appreciate all of our commercial customers. You make OpenC3 possible. Thank you."})})}),"\n",(0,i.jsx)(n.h2,{id:"faqs",children:"FAQs"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"I see both Ball Aerospace & Technologies Corp as well as OpenC3, Inc in the copyright headers. What does this mean?"}),"\n",(0,i.jsx)(n.p,{children:"OpenC3, Inc has an intellectual property agreement with BAE (formerly Ball Aerospace & Technologies Corp) which gives us the rights to commercialize the original work that we built at Ball Aerospace. Customers only need to purchase a commercial license from OpenC3."}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"What are the limits of the COSMOS Enterprise? How many users can we have? How many times can it be installed?"}),"\n",(0,i.jsx)(n.p,{children:"The COSMOS Enterprise license has no user or installation limits."}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"How is the COSMOS Enterprise license enforced?"}),"\n",(0,i.jsx)(n.p,{children:"The COSMOS Enterprise license is enforced through contract only without license managers or additional software controls."}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"How is the COSMOS Enterprise license applied? Per company? Per program?"}),"\n",(0,i.jsxs)(n.p,{children:["COSMOS Enterprise is typically licensed to a named mission or group. We also have site licenses, company licenses, and mission ops center licenses. Please contact us at ",(0,i.jsx)(n.a,{href:"mailto:sales@openc3.com",children:"sales@openc3.com"})," for more information."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Do you license to foreign companies? How do you handle ITAR or the EAR?"}),"\n",(0,i.jsxs)(n.p,{children:["We have several international customers and are not subject to ITAR export controls. We are export controlled under the EAR via ECCN 5D002c1. We have a detailed writeup explaining this justification as well as a commodity classification document from the Department of Commerce. Please contact us at ",(0,i.jsx)(n.a,{href:"mailto:sales@openc3.com",children:"sales@openc3.com"})," for more information."]}),"\n"]}),"\n"]})]})}function d(e={}){let{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},9796:function(e,n,s){s.d(n,{R:()=>l,x:()=>r});var o=s(6363);let i={},t=o.createContext(i);function l(e){let n=o.useContext(t);return o.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:l(e.components),o.createElement(t.Provider,{value:n},e.children)}}}]);
|
|
1
|
+
"use strict";(self.webpackChunkdocs_openc3_com=self.webpackChunkdocs_openc3_com||[]).push([["4189"],{4438:function(e,n,s){s.r(n),s.d(n,{metadata:()=>o,default:()=>d,frontMatter:()=>l,contentTitle:()=>r,toc:()=>c,assets:()=>a});var o=JSON.parse('{"id":"meta/licenses","title":"Licenses","description":"COSMOS licenses including the AGPLv3 vs Commercial","source":"@site/docs/meta/licenses.md","sourceDirName":"meta","slug":"/meta/licenses","permalink":"/tools/staticdocs/docs/meta/licenses","draft":false,"unlisted":false,"editUrl":"https://github.com/OpenC3/cosmos/tree/main/docs.openc3.com/docs/meta/licenses.md","tags":[],"version":"current","frontMatter":{"title":"Licenses","description":"COSMOS licenses including the AGPLv3 vs Commercial","sidebar_custom_props":{"myEmoji":"\u{1F575}\uFE0F"}},"sidebar":"defaultSidebar","previous":{"title":"Contributing","permalink":"/tools/staticdocs/docs/meta/contributing"},"next":{"title":"Philosophy","permalink":"/tools/staticdocs/docs/meta/philosophy"}}'),i=s(5656),t=s(5395);let l={title:"Licenses",description:"COSMOS licenses including the AGPLv3 vs Commercial",sidebar_custom_props:{myEmoji:"\u{1F575}\uFE0F"}},r,a={},c=[{value:"AGPLv3",id:"agplv3",level:2},{value:"Evaluation and Education Use Only",id:"evaluation-and-education-use-only",level:2},{value:"Commercial License",id:"commercial-license",level:2},{value:"Why you should buy a Commercial License",id:"why-you-should-buy-a-commercial-license",level:3},{value:"FAQs",id:"faqs",level:2}];function h(e){let n={a:"a",code:"code",em:"em",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,t.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.p,{children:"OpenC3 COSMOS is offered under a tri-licensing model allowing users to choose between the following three options:"}),"\n",(0,i.jsx)(n.h2,{id:"agplv3",children:"AGPLv3"}),"\n",(0,i.jsxs)(n.p,{children:["This is our default open source license and the license that most free users use. The AGPLv3 is a modification of the GPLv3 which is what is known as a copy-left license or a viral license. You can read the whole thing here: ",(0,i.jsx)(n.a,{href:"https://github.com/OpenC3/cosmos/blob/main/LICENSE.txt",children:"OpenC3 AGPLv3"})]}),"\n",(0,i.jsx)(n.p,{children:"Obviously, the actual license text applies, but here is a short summary:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"The AGPL allows users to use the code however they want: For business, personal, etc., as long as they follow the other terms:"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Users are anyone who could access the web-app. On the public internet, that is the whole world. On a private network, it is anyone with access to that network."}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"The software is provided as-is, no warranty"}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Users must be given access to all the source code and are also allowed to use it however they want under the same terms of the AGPLv3. This includes any modifications made, anything added, and all plugins."}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"For web applications (like COSMOS), a link must be provided to all of the source code."}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"There are some key implications of the above:"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"You cannot keep anything proprietary from your users. They have the rights to take the code (and configuration) and do anything they want with it. You CANNOT impede these rights or you are violating the AGPLv3 and YOU lose the rights to use our software."}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"You must provide a digital link to all source code for your users, including plugins."}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"All plugins must be licensed in an AGPLv3 compatible fashion. We recommend the MIT license because that allows your plugins to be compatible with the AGPLv3 and our commercial license. You can also use a dual license similar to what we do indicating the AGPLv3 or a purchased OpenC3 Commercial license."}),"\n"]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"The AGPLv3 license is often chosen because it works well for open core products like COSMOS. Competitors cannot take the open source product and license it under different terms. They would be forever locked into the AGPLv3 which is difficult to monetize, because your customers can take any code you provide and publish it on the internet for free use by everyone."}),"\n",(0,i.jsx)(n.p,{children:"As the copyright holder, OpenC3 is able to license the product and derivatives commercially. No-one else can do this. (OpenC3 is also able to license legacy Ball Aerospace COSMOS code under IP agreement)"}),"\n",(0,i.jsx)(n.h2,{id:"evaluation-and-education-use-only",children:"Evaluation and Education Use Only"}),"\n",(0,i.jsxs)(n.p,{children:["This license takes effect as soon as you use any plugin we publish under Evaluation and Education terms. Currently the only plugin we use for this is our CCSDS CFDP plugin: ",(0,i.jsx)(n.a,{href:"https://github.com/OpenC3/openc3-cosmos-cfdp",children:"CFDP Plugin"})]}),"\n",(0,i.jsx)(n.p,{children:"You can read the whole license here:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:'# OpenC3 Evaluation and Educational License\n#\n# Copyright 2023 OpenC3, Inc.\n#\n# This work is licensed for evaluation and educational purposes only.\n# It may NOT be used for formal development, integration and test, operations\n# or any other commercial purpose without the purchase of a commercial license\n# from OpenC3, Inc.\n#\n# The above copyright notice and this permission notice shall be included in all copies\n# or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\n# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n'})}),"\n",(0,i.jsx)(n.p,{children:"This license is pretty straight forward, but the key is you can't use this code for any real work leading to a product (Formal Development, Integration and Test, or Operations) unless you switch to purchasing a commercial license."}),"\n",(0,i.jsx)(n.h2,{id:"commercial-license",children:"Commercial License"}),"\n",(0,i.jsx)(n.p,{children:"This license is a signed contract with OpenC3. It allows use of our code for a program under contractual terms where you do not have to follow the AGPLv3."}),"\n",(0,i.jsx)(n.p,{children:"Generally we license to a specific project with terms that allow for unlimited users, and installs as needed by that project. Any code and plugins that you develop under the commercial license can be kept proprietary."}),"\n",(0,i.jsx)(n.p,{children:"These licenses are sold as yearly subscriptions, or as a non-expiring perpetual license. We also offer site licenses, and licenses to support unlimited missions on a government framework architecture."}),"\n",(0,i.jsx)(n.p,{children:"Of course with our commercial license, you also get all the extra functionality of our Enterprise product."}),"\n",(0,i.jsx)(n.h3,{id:"why-you-should-buy-a-commercial-license",children:"Why you should buy a Commercial License"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"You want to save years and tens of millions of dollars developing the same functionality yourself."}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"You want all of the Enterprise functionality of COSMOS Enterprise"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsx)(n.li,{children:"User Accounts"}),"\n",(0,i.jsx)(n.li,{children:"Role Based Access Control"}),"\n",(0,i.jsx)(n.li,{children:"LDAP Support"}),"\n",(0,i.jsx)(n.li,{children:"Kubernetes Support"}),"\n",(0,i.jsx)(n.li,{children:"Cloud Deployment Configurations"}),"\n",(0,i.jsx)(n.li,{children:"The right to use CFDP and other Enterprise Only plugins"}),"\n",(0,i.jsx)(n.li,{children:"Grafana Support"}),"\n",(0,i.jsx)(n.li,{children:"Support from the COSMOS Developers"}),"\n",(0,i.jsxs)(n.li,{children:["Lots more - See our ",(0,i.jsx)(n.a,{href:"https://openc3.com/enterprise",children:"Enterprise"})," page"]}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"You don't want to follow the AGPLv3"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsx)(n.li,{children:"You want to keep the code and plugins you develop proprietary"}),"\n",(0,i.jsx)(n.li,{children:"You don't want to publish an accessible link to your source code"}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"You want to support the continued development and innovation of the COSMOS product"}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.em,{children:"We appreciate all of our commercial customers. You make OpenC3 possible. Thank you."})})}),"\n",(0,i.jsx)(n.h2,{id:"faqs",children:"FAQs"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"I see both Ball Aerospace & Technologies Corp as well as OpenC3, Inc in the copyright headers. What does this mean?"}),"\n",(0,i.jsx)(n.p,{children:"OpenC3, Inc has an intellectual property agreement with BAE (formerly Ball Aerospace & Technologies Corp) which gives us the rights to commercialize the original work that we built at Ball Aerospace. Customers only need to purchase a commercial license from OpenC3."}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"What are the limits of the COSMOS Enterprise? How many users can we have? How many times can it be installed?"}),"\n",(0,i.jsx)(n.p,{children:"The COSMOS Enterprise license has no user or installation limits."}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"How is the COSMOS Enterprise license enforced?"}),"\n",(0,i.jsx)(n.p,{children:"The COSMOS Enterprise license is enforced through contract only without license managers or additional software controls."}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"How is the COSMOS Enterprise license applied? Per company? Per program?"}),"\n",(0,i.jsxs)(n.p,{children:["COSMOS Enterprise is typically licensed to a named mission or group. We also have site licenses, company licenses, and mission ops center licenses. Please contact us at ",(0,i.jsx)(n.a,{href:"mailto:sales@openc3.com",children:"sales@openc3.com"})," for more information."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Do you license to foreign companies? How do you handle ITAR or the EAR?"}),"\n",(0,i.jsxs)(n.p,{children:["We have several international customers and are not subject to ITAR export controls. We are export controlled under the EAR via ECCN 5D002c1. We have a detailed writeup explaining this justification as well as a commodity classification document from the Department of Commerce. Please contact us at ",(0,i.jsx)(n.a,{href:"mailto:sales@openc3.com",children:"sales@openc3.com"})," for more information."]}),"\n"]}),"\n"]})]})}function d(e={}){let{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},5395:function(e,n,s){s.d(n,{R:()=>l,x:()=>r});var o=s(7140);let i={},t=o.createContext(i);function l(e){let n=o.useContext(t);return o.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:l(e.components),o.createElement(t.Provider,{value:n},e.children)}}}]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";(self.webpackChunkdocs_openc3_com=self.webpackChunkdocs_openc3_com||[]).push([["7451"],{4650:function(e,n,s){s.r(n),s.d(n,{metadata:()=>o,default:()=>h,frontMatter:()=>a,contentTitle:()=>r,toc:()=>c,assets:()=>l});var o=JSON.parse('{"id":"getting-started/podman","title":"Podman","description":"Installing and running COSMOS with Podman","source":"@site/docs/getting-started/podman.md","sourceDirName":"getting-started","slug":"/getting-started/podman","permalink":"/tools/staticdocs/docs/getting-started/podman","draft":false,"unlisted":false,"editUrl":"https://github.com/OpenC3/cosmos/tree/main/docs.openc3.com/docs/getting-started/podman.md","tags":[],"version":"current","sidebarPosition":8,"frontMatter":{"sidebar_position":8,"title":"Podman","description":"Installing and running COSMOS with Podman","sidebar_custom_props":{"myEmoji":"\u{1FADB}"}},"sidebar":"defaultSidebar","previous":{"title":"Code Generators","permalink":"/tools/staticdocs/docs/getting-started/generators"},"next":{"title":"Requirements and Design","permalink":"/tools/staticdocs/docs/getting-started/requirements"}}'),t=s(7259),i=s(9796);let a={sidebar_position:8,title:"Podman",description:"Installing and running COSMOS with Podman",sidebar_custom_props:{myEmoji:"\u{1FADB}"}},r,l={},c=[{value:"OpenC3 COSMOS Using Rootless Podman and Docker-Compose",id:"openc3-cosmos-using-rootless-podman-and-docker-compose",level:3},{value:"MacOS Instructions",id:"macos-instructions",level:2}];function d(e){let n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h3,{id:"openc3-cosmos-using-rootless-podman-and-docker-compose",children:"OpenC3 COSMOS Using Rootless Podman and Docker-Compose"}),"\n",(0,t.jsx)(n.admonition,{title:"Optional Installation Option",type:"info",children:(0,t.jsx)(n.p,{children:"These directions are for installing and running COSMOS using Podman instead of Docker. If you have Docker available, that is a simpler method."})}),"\n",(0,t.jsx)(n.p,{children:"Podman is an alternative container technology to Docker that is actively promoted by RedHat. The key benefit is that Podman can run without a root-level daemon service, making it significantly more secure by design, over standard Docker. However, it is a little more complicated to use. These directions will get you up and running with Podman. The following directions have been tested against RHEL 8.8, and RHEL 9.2, but should be similar on other operating systems."}),"\n",(0,t.jsx)(n.admonition,{title:"Rootless Podman Does Not Work (Directly) with NFS Home Directories",type:"warning",children:(0,t.jsxs)(n.p,{children:["NFS does not work for holding container storage due to issues with user ids and group ids. There are workarounds available but they all involve moving container storage to another location: either a different partition on the host local disk, or into a special mounted disk image. See: [",(0,t.jsx)(n.a,{href:"https://www.redhat.com/sysadmin/rootless-podman-nfs",children:"https://www.redhat.com/sysadmin/rootless-podman-nfs"}),"]",(0,t.jsx)(n.a,{href:"https://www.redhat.com/sysadmin/rootless-podman-nfs",children:"https://www.redhat.com/sysadmin/rootless-podman-nfs"}),"). Note that there is also a newish Podman setting that allows you to more easily change where the storage location is in /etc/containers/storage.conf called rootless_storage_path. See ",(0,t.jsx)(n.a,{href:"https://www.redhat.com/sysadmin/nfs-rootless-podman",children:"https://www.redhat.com/sysadmin/nfs-rootless-podman"})]})}),"\n",(0,t.jsx)(n.h1,{id:"redhat-88-and-92-instructions",children:"Redhat 8.8 and 9.2 Instructions"}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Install Prerequisite Packages"}),"\n",(0,t.jsx)(n.p,{children:"Note: This downloads and installs docker-compose from the latest 2.x release on Github. If your operating system has a docker-compose package, it will be easier to install using that instead. RHEL8 does not have a docker-compose package."}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"sudo yum update\nsudo yum install git podman-docker netavark\ncurl -SL https://github.com/docker/compose/releases/download/v2.16.0/docker-compose-linux-x86_64 -o docker-compose\nsudo mv docker-compose /usr/local/bin/docker-compose\nsudo chmod +x /usr/local/bin/docker-compose\nsudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Configure Host OS for Redis"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"sudo su\necho never > /sys/kernel/mm/transparent_hugepage/enabled\necho never > /sys/kernel/mm/transparent_hugepage/defrag\nsysctl -w vm.max_map_count=262144\nexit\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Configure Podman to increase the PID limit"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"sudo cp /usr/share/containers/containers.conf /etc/containers/.\nsudo vi /etc/containers/containers.conf\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Then edit the ",(0,t.jsx)(n.code,{children:"pids_limit"})," value to -1 (unlimited)"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Configure Podman to use Netavark for DNS"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"sudo sh -c 'echo ip_tables > /etc/modules-load.d/ip_tables.conf'\nsudo vi /etc/containers/containers.conf\n"})}),"\n",(0,t.jsx)(n.p,{children:'Then edit the network_backend line to be "netavark" instead of "cni"'}),"\n"]}),"\n"]}),"\n",(0,t.jsx)(n.admonition,{title:"Netavark needs the ip_tables module",type:"warning",children:(0,t.jsx)(n.p,{children:'The above "echo ip_tables" line is added because RHEL 9.x uses nftables by default. The legacy ip_tables kernel module is not guaranteed to be loaded at boot \u2014 particularly on cloud images such as AWS EC2. However, netavark still requires ip_tables to implement NAT and forwarding for rootless Podman containers. Rootless users cannot load kernel modules, so if ip_tables is missing, netavark networking fails silently. If using rootless Podman with netavark ensure the ip_tables kernel module is preload.'})}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Start rootless podman socket service"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"systemctl enable --now --user podman.socket\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Put the following into your .bashrc file (or .bash_profile or whatever)"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'export DOCKER_HOST="unix://$XDG_RUNTIME_DIR/podman/podman.sock"\n'})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Source the profile file for your current terminal"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"source .bashrc\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Get COSMOS - A release or the current main branch (main branch shown)"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"git clone https://github.com/OpenC3/cosmos.git\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Optional - Set Default Container Registry"}),"\n",(0,t.jsx)(n.p,{children:"If you don't want podman to keep querying you for which registry to use, you can create a $HOME/.config/containers/registries.conf and modify to just have the main docker registry (or modify the /etc/containers/registries.conf file directly)"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"mkdir -p $HOME/.config/containers\ncp /etc/containers/registries.conf $HOME/.config/containers/.\nvi $HOME/.config/containers/registries.conf\n"})}),"\n",(0,t.jsx)(n.p,{children:"Then edit the unqualified-search-registries = line to just have the registry you care about (probably docker.io)"}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Edit cosmos/compose.yaml"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"cd cosmos\nvi compose.yaml\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Edit compose.yaml and uncomment the user: 0:0 lines and comment the user: ",(0,t.jsx)(n.code,{children:'"${OPENC3_USER_ID}:${OPENC3_GROUP_ID}"'})," lines.\nYou may also want to update the traefik configuration to allow access from the internet by removing 127.0.0.1 and probably switching to either an SSL config file, or the allow http one. Also make sure your firewall allows\nwhatever port you choose to use in. Rootless podman will need to use a higher numbered port (not 1-1023)."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Run COSMOS"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"./openc3.sh run\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:["Wait until everything is built and running and then goto ",(0,t.jsx)(n.a,{href:"http://localhost:2900",children:"http://localhost:2900"})," in your browser"]}),"\n"]}),"\n"]}),"\n",(0,t.jsx)(n.admonition,{title:"Podman on MacOS",type:"info",children:(0,t.jsx)(n.p,{children:"Podman can also be used on MacOS, though we still generally recommend Docker Desktop"})}),"\n",(0,t.jsx)(n.h2,{id:"macos-instructions",children:"MacOS Instructions"}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Install podman"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"brew install podman\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Start the podman virtual machine"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"podman machine init\npodman machine start\n# Note: update to your username in the next line or copy paste from what 'podman machine start' says\nexport DOCKER_HOST='unix:///Users/ryanmelt/.local/share/containers/podman/machine/qemu/podman.sock'\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Install docker-compose"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"brew install docker-compose # Optional if you already have Docker Desktop\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Edit cosmos/compose.yaml"}),"\n",(0,t.jsxs)(n.p,{children:["Edit compose.yaml and uncomment the user: 0:0 lines and comment the user: ",(0,t.jsx)(n.code,{children:'"${OPENC3_USER_ID}:${OPENC3_GROUP_ID}"'})," lines."]}),"\n",(0,t.jsxs)(n.p,{children:["Important: on MacOS you must also remove all ",":z"," from the volume mount lines"]}),"\n",(0,t.jsx)(n.p,{children:"You may also want to update the traefik configuration to allow access from the internet."}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Run COSMOS"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"cd cosmos\n./openc3.sh run\n"})}),"\n"]}),"\n"]})]})}function h(e={}){let{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},9796:function(e,n,s){s.d(n,{R:()=>a,x:()=>r});var o=s(6363);let t={},i=o.createContext(t);function a(e){let n=o.useContext(i);return o.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:a(e.components),o.createElement(i.Provider,{value:n},e.children)}}}]);
|
|
1
|
+
"use strict";(self.webpackChunkdocs_openc3_com=self.webpackChunkdocs_openc3_com||[]).push([["7451"],{9877:function(e,n,s){s.r(n),s.d(n,{metadata:()=>o,default:()=>h,frontMatter:()=>a,contentTitle:()=>r,toc:()=>c,assets:()=>l});var o=JSON.parse('{"id":"getting-started/podman","title":"Podman","description":"Installing and running COSMOS with Podman","source":"@site/docs/getting-started/podman.md","sourceDirName":"getting-started","slug":"/getting-started/podman","permalink":"/tools/staticdocs/docs/getting-started/podman","draft":false,"unlisted":false,"editUrl":"https://github.com/OpenC3/cosmos/tree/main/docs.openc3.com/docs/getting-started/podman.md","tags":[],"version":"current","sidebarPosition":8,"frontMatter":{"sidebar_position":8,"title":"Podman","description":"Installing and running COSMOS with Podman","sidebar_custom_props":{"myEmoji":"\u{1FADB}"}},"sidebar":"defaultSidebar","previous":{"title":"Code Generators","permalink":"/tools/staticdocs/docs/getting-started/generators"},"next":{"title":"Requirements and Design","permalink":"/tools/staticdocs/docs/getting-started/requirements"}}'),t=s(5656),i=s(5395);let a={sidebar_position:8,title:"Podman",description:"Installing and running COSMOS with Podman",sidebar_custom_props:{myEmoji:"\u{1FADB}"}},r,l={},c=[{value:"OpenC3 COSMOS Using Rootless Podman and Docker-Compose",id:"openc3-cosmos-using-rootless-podman-and-docker-compose",level:3},{value:"MacOS Instructions",id:"macos-instructions",level:2}];function d(e){let n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h3,{id:"openc3-cosmos-using-rootless-podman-and-docker-compose",children:"OpenC3 COSMOS Using Rootless Podman and Docker-Compose"}),"\n",(0,t.jsx)(n.admonition,{title:"Optional Installation Option",type:"info",children:(0,t.jsx)(n.p,{children:"These directions are for installing and running COSMOS using Podman instead of Docker. If you have Docker available, that is a simpler method."})}),"\n",(0,t.jsx)(n.p,{children:"Podman is an alternative container technology to Docker that is actively promoted by RedHat. The key benefit is that Podman can run without a root-level daemon service, making it significantly more secure by design, over standard Docker. However, it is a little more complicated to use. These directions will get you up and running with Podman. The following directions have been tested against RHEL 8.8, and RHEL 9.2, but should be similar on other operating systems."}),"\n",(0,t.jsx)(n.admonition,{title:"Rootless Podman Does Not Work (Directly) with NFS Home Directories",type:"warning",children:(0,t.jsxs)(n.p,{children:["NFS does not work for holding container storage due to issues with user ids and group ids. There are workarounds available but they all involve moving container storage to another location: either a different partition on the host local disk, or into a special mounted disk image. See: [",(0,t.jsx)(n.a,{href:"https://www.redhat.com/sysadmin/rootless-podman-nfs",children:"https://www.redhat.com/sysadmin/rootless-podman-nfs"}),"]",(0,t.jsx)(n.a,{href:"https://www.redhat.com/sysadmin/rootless-podman-nfs",children:"https://www.redhat.com/sysadmin/rootless-podman-nfs"}),"). Note that there is also a newish Podman setting that allows you to more easily change where the storage location is in /etc/containers/storage.conf called rootless_storage_path. See ",(0,t.jsx)(n.a,{href:"https://www.redhat.com/sysadmin/nfs-rootless-podman",children:"https://www.redhat.com/sysadmin/nfs-rootless-podman"})]})}),"\n",(0,t.jsx)(n.h1,{id:"redhat-88-and-92-instructions",children:"Redhat 8.8 and 9.2 Instructions"}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Install Prerequisite Packages"}),"\n",(0,t.jsx)(n.p,{children:"Note: This downloads and installs docker-compose from the latest 2.x release on Github. If your operating system has a docker-compose package, it will be easier to install using that instead. RHEL8 does not have a docker-compose package."}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"sudo yum update\nsudo yum install git podman-docker netavark\ncurl -SL https://github.com/docker/compose/releases/download/v2.16.0/docker-compose-linux-x86_64 -o docker-compose\nsudo mv docker-compose /usr/local/bin/docker-compose\nsudo chmod +x /usr/local/bin/docker-compose\nsudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Configure Host OS for Redis"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"sudo su\necho never > /sys/kernel/mm/transparent_hugepage/enabled\necho never > /sys/kernel/mm/transparent_hugepage/defrag\nsysctl -w vm.max_map_count=262144\nexit\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Configure Podman to increase the PID limit"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"sudo cp /usr/share/containers/containers.conf /etc/containers/.\nsudo vi /etc/containers/containers.conf\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Then edit the ",(0,t.jsx)(n.code,{children:"pids_limit"})," value to -1 (unlimited)"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Configure Podman to use Netavark for DNS"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"sudo sh -c 'echo ip_tables > /etc/modules-load.d/ip_tables.conf'\nsudo vi /etc/containers/containers.conf\n"})}),"\n",(0,t.jsx)(n.p,{children:'Then edit the network_backend line to be "netavark" instead of "cni"'}),"\n"]}),"\n"]}),"\n",(0,t.jsx)(n.admonition,{title:"Netavark needs the ip_tables module",type:"warning",children:(0,t.jsx)(n.p,{children:'The above "echo ip_tables" line is added because RHEL 9.x uses nftables by default. The legacy ip_tables kernel module is not guaranteed to be loaded at boot \u2014 particularly on cloud images such as AWS EC2. However, netavark still requires ip_tables to implement NAT and forwarding for rootless Podman containers. Rootless users cannot load kernel modules, so if ip_tables is missing, netavark networking fails silently. If using rootless Podman with netavark ensure the ip_tables kernel module is preload.'})}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Start rootless podman socket service"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"systemctl enable --now --user podman.socket\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Put the following into your .bashrc file (or .bash_profile or whatever)"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'export DOCKER_HOST="unix://$XDG_RUNTIME_DIR/podman/podman.sock"\n'})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Source the profile file for your current terminal"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"source .bashrc\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Get COSMOS - A release or the current main branch (main branch shown)"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"git clone https://github.com/OpenC3/cosmos.git\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Optional - Set Default Container Registry"}),"\n",(0,t.jsx)(n.p,{children:"If you don't want podman to keep querying you for which registry to use, you can create a $HOME/.config/containers/registries.conf and modify to just have the main docker registry (or modify the /etc/containers/registries.conf file directly)"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"mkdir -p $HOME/.config/containers\ncp /etc/containers/registries.conf $HOME/.config/containers/.\nvi $HOME/.config/containers/registries.conf\n"})}),"\n",(0,t.jsx)(n.p,{children:"Then edit the unqualified-search-registries = line to just have the registry you care about (probably docker.io)"}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Edit cosmos/compose.yaml"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"cd cosmos\nvi compose.yaml\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Edit compose.yaml and uncomment the user: 0:0 lines and comment the user: ",(0,t.jsx)(n.code,{children:'"${OPENC3_USER_ID}:${OPENC3_GROUP_ID}"'})," lines.\nYou may also want to update the traefik configuration to allow access from the internet by removing 127.0.0.1 and probably switching to either an SSL config file, or the allow http one. Also make sure your firewall allows\nwhatever port you choose to use in. Rootless podman will need to use a higher numbered port (not 1-1023)."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Run COSMOS"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"./openc3.sh run\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:["Wait until everything is built and running and then goto ",(0,t.jsx)(n.a,{href:"http://localhost:2900",children:"http://localhost:2900"})," in your browser"]}),"\n"]}),"\n"]}),"\n",(0,t.jsx)(n.admonition,{title:"Podman on MacOS",type:"info",children:(0,t.jsx)(n.p,{children:"Podman can also be used on MacOS, though we still generally recommend Docker Desktop"})}),"\n",(0,t.jsx)(n.h2,{id:"macos-instructions",children:"MacOS Instructions"}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Install podman"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"brew install podman\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Start the podman virtual machine"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"podman machine init\npodman machine start\n# Note: update to your username in the next line or copy paste from what 'podman machine start' says\nexport DOCKER_HOST='unix:///Users/ryanmelt/.local/share/containers/podman/machine/qemu/podman.sock'\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Install docker-compose"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"brew install docker-compose # Optional if you already have Docker Desktop\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Edit cosmos/compose.yaml"}),"\n",(0,t.jsxs)(n.p,{children:["Edit compose.yaml and uncomment the user: 0:0 lines and comment the user: ",(0,t.jsx)(n.code,{children:'"${OPENC3_USER_ID}:${OPENC3_GROUP_ID}"'})," lines."]}),"\n",(0,t.jsxs)(n.p,{children:["Important: on MacOS you must also remove all ",":z"," from the volume mount lines"]}),"\n",(0,t.jsx)(n.p,{children:"You may also want to update the traefik configuration to allow access from the internet."}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Run COSMOS"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"cd cosmos\n./openc3.sh run\n"})}),"\n"]}),"\n"]})]})}function h(e={}){let{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},5395:function(e,n,s){s.d(n,{R:()=>a,x:()=>r});var o=s(7140);let t={},i=o.createContext(t);function a(e){let n=o.useContext(i);return o.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:a(e.components),o.createElement(i.Provider,{value:n},e.children)}}}]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";(self.webpackChunkdocs_openc3_com=self.webpackChunkdocs_openc3_com||[]).push([["9621"],{3899:function(e,n,t){t.r(n),t.d(n,{metadata:()=>i,default:()=>h,frontMatter:()=>r,contentTitle:()=>o,toc:()=>d,assets:()=>c});var i=JSON.parse('{"id":"development/streaming-api","title":"Streaming API","description":"Using the websocket streaming API to retrieve data","source":"@site/docs/development/streaming-api.md","sourceDirName":"development","slug":"/development/streaming-api","permalink":"/tools/staticdocs/docs/development/streaming-api","draft":false,"unlisted":false,"editUrl":"https://github.com/OpenC3/cosmos/tree/main/docs.openc3.com/docs/development/streaming-api.md","tags":[],"version":"current","frontMatter":{"title":"Streaming API","description":"Using the websocket streaming API to retrieve data","sidebar_custom_props":{"myEmoji":"\u{1F4DD}"}},"sidebar":"defaultSidebar","previous":{"title":"Roadmap","permalink":"/tools/staticdocs/docs/development/roadmap"},"next":{"title":"Testing COSMOS","permalink":"/tools/staticdocs/docs/development/testing"}}'),a=t(7259),s=t(9796);let r={title:"Streaming API",description:"Using the websocket streaming API to retrieve data",sidebar_custom_props:{myEmoji:"\u{1F4DD}"}},o,c={},d=[{value:"Ruby Example",id:"ruby-example",level:2},{value:"StreamingApi Architecture",id:"streamingapi-architecture",level:2},{value:"Architecture Overview",id:"architecture-overview",level:3},{value:"Key Components",id:"key-components",level:3},{value:"StreamingApi",id:"streamingapi",level:4},{value:"StreamingThread",id:"streamingthread",level:4},{value:"RealtimeStreamingThread",id:"realtimestreamingthread",level:4},{value:"LoggedStreamingThread",id:"loggedstreamingthread",level:4},{value:"StreamingObject",id:"streamingobject",level:4},{value:"StreamingObjectCollection",id:"streamingobjectcollection",level:4},{value:"Data Flow",id:"data-flow",level:3},{value:"Performance Considerations",id:"performance-considerations",level:3},{value:"Security",id:"security",level:3}];function l(e){let n={admonition:"admonition",code:"code",h2:"h2",h3:"h3",h4:"h4",li:"li",ol:"ol",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n.admonition,{title:"This documentation is for COSMOS Developers",type:"note",children:(0,a.jsx)(n.p,{children:"This information is just generally used behind the scenes in COSMOS tools"})}),"\n",(0,a.jsx)(n.p,{children:"The COSMOS Streaming Api is the primary interface to receive a stream of the telemetry packets and/or command packets that have passed through the COSMOS system, both logged and continuously in realtime. Either raw binary packets or decommutated JSON packets can be requested."}),"\n",(0,a.jsx)(n.p,{children:"This API is implemented over Websockets using the Rails ActionCable framework. Actioncable client libraries are known to exist for at least Javascript, Ruby, and Python. Other languages may exist or could be created. Websockets allow for easy interaction with the new COSMOS Javascript based frontend."}),"\n",(0,a.jsx)(n.p,{children:"The following interactions are all shown in Javascript, but would be very similar in any language.\nConnecting to this API begins by initiating an ActionCable connection."}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{children:"cable = ActionCable.createConsumer('/openc3-api/cable')\n"})}),"\n",(0,a.jsx)(n.p,{children:"This call opens the HTTP connection to the given URL and upgrades it to a websocket connection. This connection can then be shared with multiple \u201Csubscriptions\u201D."}),"\n",(0,a.jsx)(n.p,{children:"A subscription describes a set of data that you want the API to stream to you. Creating a subscription looks like this:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-javascript",children:'subscription = cable.subscriptions.create(\n {\n channel: "StreamingChannel",\n scope: "DEFAULT",\n token: token,\n },\n {\n received: (data) => {\n // Handle received data\n },\n connected: () => {\n // First chance to add what you want to stream here\n },\n disconnected: () => {\n // Handle the subscription being disconnected\n },\n rejected: () => {\n // Handle the subscription being rejected\n },\n }\n);\n'})}),"\n",(0,a.jsxs)(n.p,{children:["Subscribing to the StreamingApi requires passing a channel name set to \u201CStreamingChannel\u201D, a scope which is typically \u201CDEFAULT\u201D, and an access token (a password in COSMOS Core). In Javascript you also pass a set of callback functions that run at various lifecycle points in the subscription. The most important of these are ",(0,a.jsx)(n.code,{children:"connected"})," and ",(0,a.jsx)(n.code,{children:"received"}),"."]}),"\n",(0,a.jsxs)(n.p,{children:[(0,a.jsx)(n.code,{children:"connected"})," runs when the subscription is accepted by the StreamApi. This callback is the first opportunity to request specific data that you would like streamed. Data can also be added or removed at any time while the subscription is open."]}),"\n",(0,a.jsx)(n.p,{children:"Data can be added to the stream by requesting individual items from a packet or by requesting the entire packet."}),"\n",(0,a.jsx)(n.p,{children:"Adding items to stream is done as follows:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-javascript",children:'var items = [\n ["DECOM__TLM__INST__ADCS__Q1__RAW", "0"],\n ["DECOM__CMD__INST__COLLECT__DURATION__WITH_UNITS", "1"],\n];\nOpenC3Auth.updateToken(OpenC3Auth.defaultMinValidity).then(() => {\n this.subscription.perform("add", {\n scope: window.openc3Scope,\n token: localStorage.openc3Token,\n items: items,\n start_time: this.startDateTime,\n end_time: this.endDateTime,\n });\n});\n'})}),"\n",(0,a.jsxs)(n.p,{children:["The values in the item name are separated by double underscores, e.g. ",(0,a.jsx)(n.code,{children:"<MODE>__<CMD or TLM>__<TARGET NAME>__<PACKET NAME>__<ITEM NAME>__<VALUE TYPE>__<REDUCED TYPE>"}),". Mode is either RAW, DECOM, REDUCED_MINUTE, REDUCED_HOUR, or REDUCED_DAY. The next parameter is CMD or TLM followed by the target, packet and item names. The Value Type is one of RAW, CONVERTED, FORMATTED, or WITH_UNITS. The last parameter is optional if you want to use the reduced data types. Reduced Type is one of SAMPLE, MIN, MAX, AVG, or STDDEV."]}),"\n",(0,a.jsx)(n.p,{children:"Adding packets to stream is done as follows:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-javascript",children:'var packets = [\n ["RAW__TLM__INST__ADCS", "0"],\n ["DECOM__TLM__INST__HEALTH_STATUS__FORMATTED", "1"],\n];\nOpenC3Auth.updateToken(OpenC3Auth.defaultMinValidity).then(() => {\n this.subscription.perform("add", {\n scope: window.openc3Scope,\n token: localStorage.openc3Token,\n packets: packets,\n start_time: this.startDateTime,\n end_time: this.endDateTime,\n });\n});\n'})}),"\n",(0,a.jsxs)(n.p,{children:["The values in the packet name are separated by double underscores, e.g. ",(0,a.jsx)(n.code,{children:"<MODE>__<CMD or TLM>__<TARGET NAME>__<PACKET NAME>__<VALUE TYPE>"}),". Mode is either RAW or DECOM. The next parameter is CMD or TLM followed by the target and packet names. The Value Type is one of RAW, CONVERTED, FORMATTED, or WITH_UNITS."]}),"\n",(0,a.jsx)(n.p,{children:"For Raw mode, VALUE TYPE should be set to RAW or omitted (e.g. TLM__INST__ADCS__RAW or TLM__INST__ADCS).\nstart_time and end_time are standard COSMOS 64-bit integer timestamps in nanoseconds since the Unix Epoch (midnight January 1st, 1970). If start_time is null, that indicates to start streaming from the current time in realtime, indefinitely until items are removed, or the subscription is unsubscribed. end_time is ignored if start_time is null. If start_time is given and end_time is null, that indicates to playback from the given starttime and then continue indefinitely in realtime. If both start_time and end_time are given, then that indicates a temporary playback of historical data."}),"\n",(0,a.jsx)(n.p,{children:"Data returned by the streaming API is handled by the received callback in Javascript. Data is returned as a JSON Array, with a JSON object in the array for each packet returned. Results are batched, and the current implementation will return up to 100 packets in each batch (the array will have 100 entries). 100 packets per batch is not guaranteed, and batches may take on varying sizes based on the size of the data returned, or other factors. An empty array indicates that all data has been sent for a purely historical query and can be used as an end of data indicator."}),"\n",(0,a.jsx)(n.p,{children:"For decommutated items, each packet is represented as a JSON object with a 'time' field holding the COSMOS nanosecond timestamp of the packet, and then each of the requested item keys with their corresponding value from the packet."}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'[\n {\n "time": 1234657585858,\n "TLM__INST__ADCS__Q1__RAW": 50.0,\n "TLM__INST__ADCS__Q2__RAW": 100.0\n },\n {\n "time": 1234657585859,\n "TLM__INST__ADCS__Q1__RAW": 60.0,\n "TLM__INST__ADCS__Q2__RAW": 110.0\n }\n]\n'})}),"\n",(0,a.jsx)(n.p,{children:"For raw packets, each packet is represented as a JSON object with a time field holding the COSMOS nanosecond timestamp of the packet, a packet field holding the topic the packet was read from in the form of SCOPE__TELEMETRY__TARGETNAME__PACKETNAME, and a buffer field holding a BASE64 encoded copy of the packet data."}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'[\n {\n "time": 1234657585858,\n "packet": "DEFAULT__TELEMETRY__INST__ADCS",\n "buffer": "SkdfjGodkdfjdfoekfsg"\n },\n {\n "time": 1234657585859,\n "packet": "DEFAULT__TELEMETRY__INST__ADCS",\n "buffer": "3i5n49dmnfg9fl32k3"\n }\n]\n'})}),"\n",(0,a.jsx)(n.h2,{id:"ruby-example",children:"Ruby Example"}),"\n",(0,a.jsx)(n.p,{children:"Below is a simple Ruby example for using the streaming API to retrieve telemetry data:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-ruby",children:"require 'openc3'\nrequire 'openc3/script/web_socket_api'\n\n$openc3_scope = 'DEFAULT'\nENV['OPENC3_API_HOSTNAME'] = '127.0.0.1'\nENV['OPENC3_API_PORT'] = '2900'\nENV['OPENC3_API_PASSWORD'] = 'password'\n# The following are needed for Enterprise (change user/pass as necessary)\n#ENV['OPENC3_API_USER'] = 'operator'\n#ENV['OPENC3_API_PASSWORD'] = 'operator'\n#ENV['OPENC3_KEYCLOAK_REALM'] = 'openc3'\n#ENV['OPENC3_KEYCLOAK_URL'] = 'http://127.0.0.1:2900/auth'\n\n# Open a file to write CSV data\ncsv = File.open('telemetry_data.csv', 'w')\n\n# Connect to the streaming API\nOpenC3::StreamingWebSocketApi.new() do |api|\n # Add items to stream - request data from yesterday to 1 minute ago\n api.add(items: [\n 'DECOM__TLM__INST__HEALTH_STATUS__TEMP1__CONVERTED',\n 'DECOM__TLM__INST__HEALTH_STATUS__TEMP2__CONVERTED'\n ],\n start_time: (Time.now - 86400).to_nsec_from_epoch, # 24 hours ago\n end_time: (Time.now - 60).to_nsec_from_epoch) # 1 minute ago\n\n # Write CSV header\n csv.puts \"Time,TEMP1,TEMP2\"\n\n # Read all data from the stream\n data = api.read\n\n # Process each data point\n data.each do |item|\n csv.puts \"#{item['__time']/1_000_000_000.0},#{item['DECOM__TLM__INST__HEALTH_STATUS__TEMP1__CONVERTED']},#{item['DECOM__TLM__INST__HEALTH_STATUS__TEMP2__CONVERTED']}\"\n end\nend\ncsv.close()\n"})}),"\n",(0,a.jsx)(n.h2,{id:"streamingapi-architecture",children:"StreamingApi Architecture"}),"\n",(0,a.jsx)(n.p,{children:"The StreamingApi is a core component of COSMOS that provides real-time and historical data streaming capabilities. Below is an overview of its architecture and design."}),"\n",(0,a.jsx)(n.h3,{id:"architecture-overview",children:"Architecture Overview"}),"\n",(0,a.jsx)(n.p,{children:"The StreamingApi uses a modular architecture with several key components:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{children:"StreamingApi\n\u251C\u2500\u2500 StreamingThread (abstract)\n\u2502 \u251C\u2500\u2500 RealtimeStreamingThread\n\u2502 \u2514\u2500\u2500 LoggedStreamingThread\n\u2514\u2500\u2500 StreamingObjectCollection\n \u2514\u2500\u2500 StreamingObject\n"})}),"\n",(0,a.jsx)(n.h3,{id:"key-components",children:"Key Components"}),"\n",(0,a.jsx)(n.h4,{id:"streamingapi",children:"StreamingApi"}),"\n",(0,a.jsx)(n.p,{children:"The main class that manages streaming connections and handles client requests:"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:"Initializes with a client UUID, channel, and scope"}),"\n",(0,a.jsx)(n.li,{children:"Manages thread lifecycle for both real-time and historical data"}),"\n",(0,a.jsx)(n.li,{children:"Processes client requests to add or remove data streams"}),"\n",(0,a.jsx)(n.li,{children:"Coordinates handoff from historical to real-time streaming"}),"\n",(0,a.jsx)(n.li,{children:"Sends batched data back to clients via ActionCable"}),"\n"]}),"\n",(0,a.jsx)(n.h4,{id:"streamingthread",children:"StreamingThread"}),"\n",(0,a.jsx)(n.p,{children:"Abstract base class that defines common thread functionality:"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:"Manages thread lifecycle (start, stop)"}),"\n",(0,a.jsx)(n.li,{children:"Processes data from various sources"}),"\n",(0,a.jsx)(n.li,{children:"Handles batching and transmission of results"}),"\n",(0,a.jsx)(n.li,{children:"Determines when streaming is complete"}),"\n"]}),"\n",(0,a.jsx)(n.h4,{id:"realtimestreamingthread",children:"RealtimeStreamingThread"}),"\n",(0,a.jsx)(n.p,{children:"Specialized thread for real-time data:"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:"Subscribes to Redis topics"}),"\n",(0,a.jsx)(n.li,{children:"Processes incoming messages in real-time"}),"\n",(0,a.jsx)(n.li,{children:"Continuous streaming from current time"}),"\n"]}),"\n",(0,a.jsx)(n.h4,{id:"loggedstreamingthread",children:"LoggedStreamingThread"}),"\n",(0,a.jsx)(n.p,{children:"Specialized thread for historical data:"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:"Reads from archived log files"}),"\n",(0,a.jsx)(n.li,{children:"Handles time-based sorting of data"}),"\n",(0,a.jsx)(n.li,{children:"Transitions to real-time streaming when historical data is exhausted"}),"\n"]}),"\n",(0,a.jsx)(n.h4,{id:"streamingobject",children:"StreamingObject"}),"\n",(0,a.jsx)(n.p,{children:"Represents a single subscription item:"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:"Parses and validates stream keys"}),"\n",(0,a.jsx)(n.li,{children:"Stores metadata about the stream (mode, target, packet, item)"}),"\n",(0,a.jsx)(n.li,{children:"Tracks timestamps and offsets"}),"\n",(0,a.jsx)(n.li,{children:"Handles authorization"}),"\n"]}),"\n",(0,a.jsx)(n.h4,{id:"streamingobjectcollection",children:"StreamingObjectCollection"}),"\n",(0,a.jsx)(n.p,{children:"Manages groups of StreamingObjects:"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:"Organizes objects by topic"}),"\n",(0,a.jsx)(n.li,{children:"Tracks collective state"}),"\n",(0,a.jsx)(n.li,{children:"Provides efficient lookups"}),"\n"]}),"\n",(0,a.jsx)(n.h3,{id:"data-flow",children:"Data Flow"}),"\n",(0,a.jsxs)(n.ol,{children:["\n",(0,a.jsx)(n.li,{children:"Client connects to ActionCable and subscribes to StreamingChannel"}),"\n",(0,a.jsx)(n.li,{children:"Client sends 'add' request with items/packets to stream"}),"\n",(0,a.jsx)(n.li,{children:"StreamingApi creates appropriate StreamingObjects with authorization"}),"\n",(0,a.jsxs)(n.li,{children:["For historical requests:","\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:"LoggedStreamingThread reads from log files"}),"\n",(0,a.jsx)(n.li,{children:"Data is sent in batches to client"}),"\n",(0,a.jsx)(n.li,{children:"When historical data is exhausted, handoff to real-time"}),"\n"]}),"\n"]}),"\n",(0,a.jsxs)(n.li,{children:["For real-time requests:","\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:"RealtimeStreamingThread subscribes to Redis topics"}),"\n",(0,a.jsx)(n.li,{children:"Data is sent to client as it arrives"}),"\n"]}),"\n"]}),"\n",(0,a.jsx)(n.li,{children:"Client can add/remove items at any time"}),"\n",(0,a.jsx)(n.li,{children:"When client disconnects, all threads are terminated"}),"\n"]}),"\n",(0,a.jsx)(n.h3,{id:"performance-considerations",children:"Performance Considerations"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:"Uses thread-per-request model for historical data"}),"\n",(0,a.jsx)(n.li,{children:"Maintains a single thread for real-time data"}),"\n",(0,a.jsx)(n.li,{children:"Batches results to reduce network overhead (up to 100 items per batch)"}),"\n",(0,a.jsx)(n.li,{children:"File caching for efficient historical data access"}),"\n",(0,a.jsx)(n.li,{children:"Seamless transition from historical to real-time data"}),"\n"]}),"\n",(0,a.jsx)(n.h3,{id:"security",children:"Security"}),"\n",(0,a.jsx)(n.p,{children:"Every StreamingObject verifies authorization for the specific target and packet being requested, ensuring users only access data they have permission to view."})]})}function h(e={}){let{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,a.jsx)(n,{...e,children:(0,a.jsx)(l,{...e})}):l(e)}},9796:function(e,n,t){t.d(n,{R:()=>r,x:()=>o});var i=t(6363);let a={},s=i.createContext(a);function r(e){let n=i.useContext(s);return i.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:r(e.components),i.createElement(s.Provider,{value:n},e.children)}}}]);
|
|
1
|
+
"use strict";(self.webpackChunkdocs_openc3_com=self.webpackChunkdocs_openc3_com||[]).push([["9621"],{1810:function(e,n,t){t.r(n),t.d(n,{metadata:()=>i,default:()=>h,frontMatter:()=>r,contentTitle:()=>o,toc:()=>d,assets:()=>c});var i=JSON.parse('{"id":"development/streaming-api","title":"Streaming API","description":"Using the websocket streaming API to retrieve data","source":"@site/docs/development/streaming-api.md","sourceDirName":"development","slug":"/development/streaming-api","permalink":"/tools/staticdocs/docs/development/streaming-api","draft":false,"unlisted":false,"editUrl":"https://github.com/OpenC3/cosmos/tree/main/docs.openc3.com/docs/development/streaming-api.md","tags":[],"version":"current","frontMatter":{"title":"Streaming API","description":"Using the websocket streaming API to retrieve data","sidebar_custom_props":{"myEmoji":"\u{1F4DD}"}},"sidebar":"defaultSidebar","previous":{"title":"Roadmap","permalink":"/tools/staticdocs/docs/development/roadmap"},"next":{"title":"Testing COSMOS","permalink":"/tools/staticdocs/docs/development/testing"}}'),a=t(5656),s=t(5395);let r={title:"Streaming API",description:"Using the websocket streaming API to retrieve data",sidebar_custom_props:{myEmoji:"\u{1F4DD}"}},o,c={},d=[{value:"Ruby Example",id:"ruby-example",level:2},{value:"StreamingApi Architecture",id:"streamingapi-architecture",level:2},{value:"Architecture Overview",id:"architecture-overview",level:3},{value:"Key Components",id:"key-components",level:3},{value:"StreamingApi",id:"streamingapi",level:4},{value:"StreamingThread",id:"streamingthread",level:4},{value:"RealtimeStreamingThread",id:"realtimestreamingthread",level:4},{value:"LoggedStreamingThread",id:"loggedstreamingthread",level:4},{value:"StreamingObject",id:"streamingobject",level:4},{value:"StreamingObjectCollection",id:"streamingobjectcollection",level:4},{value:"Data Flow",id:"data-flow",level:3},{value:"Performance Considerations",id:"performance-considerations",level:3},{value:"Security",id:"security",level:3}];function l(e){let n={admonition:"admonition",code:"code",h2:"h2",h3:"h3",h4:"h4",li:"li",ol:"ol",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n.admonition,{title:"This documentation is for COSMOS Developers",type:"note",children:(0,a.jsx)(n.p,{children:"This information is just generally used behind the scenes in COSMOS tools"})}),"\n",(0,a.jsx)(n.p,{children:"The COSMOS Streaming Api is the primary interface to receive a stream of the telemetry packets and/or command packets that have passed through the COSMOS system, both logged and continuously in realtime. Either raw binary packets or decommutated JSON packets can be requested."}),"\n",(0,a.jsx)(n.p,{children:"This API is implemented over Websockets using the Rails ActionCable framework. Actioncable client libraries are known to exist for at least Javascript, Ruby, and Python. Other languages may exist or could be created. Websockets allow for easy interaction with the new COSMOS Javascript based frontend."}),"\n",(0,a.jsx)(n.p,{children:"The following interactions are all shown in Javascript, but would be very similar in any language.\nConnecting to this API begins by initiating an ActionCable connection."}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{children:"cable = ActionCable.createConsumer('/openc3-api/cable')\n"})}),"\n",(0,a.jsx)(n.p,{children:"This call opens the HTTP connection to the given URL and upgrades it to a websocket connection. This connection can then be shared with multiple \u201Csubscriptions\u201D."}),"\n",(0,a.jsx)(n.p,{children:"A subscription describes a set of data that you want the API to stream to you. Creating a subscription looks like this:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-javascript",children:'subscription = cable.subscriptions.create(\n {\n channel: "StreamingChannel",\n scope: "DEFAULT",\n token: token,\n },\n {\n received: (data) => {\n // Handle received data\n },\n connected: () => {\n // First chance to add what you want to stream here\n },\n disconnected: () => {\n // Handle the subscription being disconnected\n },\n rejected: () => {\n // Handle the subscription being rejected\n },\n }\n);\n'})}),"\n",(0,a.jsxs)(n.p,{children:["Subscribing to the StreamingApi requires passing a channel name set to \u201CStreamingChannel\u201D, a scope which is typically \u201CDEFAULT\u201D, and an access token (a password in COSMOS Core). In Javascript you also pass a set of callback functions that run at various lifecycle points in the subscription. The most important of these are ",(0,a.jsx)(n.code,{children:"connected"})," and ",(0,a.jsx)(n.code,{children:"received"}),"."]}),"\n",(0,a.jsxs)(n.p,{children:[(0,a.jsx)(n.code,{children:"connected"})," runs when the subscription is accepted by the StreamApi. This callback is the first opportunity to request specific data that you would like streamed. Data can also be added or removed at any time while the subscription is open."]}),"\n",(0,a.jsx)(n.p,{children:"Data can be added to the stream by requesting individual items from a packet or by requesting the entire packet."}),"\n",(0,a.jsx)(n.p,{children:"Adding items to stream is done as follows:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-javascript",children:'var items = [\n ["DECOM__TLM__INST__ADCS__Q1__RAW", "0"],\n ["DECOM__CMD__INST__COLLECT__DURATION__WITH_UNITS", "1"],\n];\nOpenC3Auth.updateToken(OpenC3Auth.defaultMinValidity).then(() => {\n this.subscription.perform("add", {\n scope: window.openc3Scope,\n token: localStorage.openc3Token,\n items: items,\n start_time: this.startDateTime,\n end_time: this.endDateTime,\n });\n});\n'})}),"\n",(0,a.jsxs)(n.p,{children:["The values in the item name are separated by double underscores, e.g. ",(0,a.jsx)(n.code,{children:"<MODE>__<CMD or TLM>__<TARGET NAME>__<PACKET NAME>__<ITEM NAME>__<VALUE TYPE>__<REDUCED TYPE>"}),". Mode is either RAW, DECOM, REDUCED_MINUTE, REDUCED_HOUR, or REDUCED_DAY. The next parameter is CMD or TLM followed by the target, packet and item names. The Value Type is one of RAW, CONVERTED, FORMATTED, or WITH_UNITS. The last parameter is optional if you want to use the reduced data types. Reduced Type is one of SAMPLE, MIN, MAX, AVG, or STDDEV."]}),"\n",(0,a.jsx)(n.p,{children:"Adding packets to stream is done as follows:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-javascript",children:'var packets = [\n ["RAW__TLM__INST__ADCS", "0"],\n ["DECOM__TLM__INST__HEALTH_STATUS__FORMATTED", "1"],\n];\nOpenC3Auth.updateToken(OpenC3Auth.defaultMinValidity).then(() => {\n this.subscription.perform("add", {\n scope: window.openc3Scope,\n token: localStorage.openc3Token,\n packets: packets,\n start_time: this.startDateTime,\n end_time: this.endDateTime,\n });\n});\n'})}),"\n",(0,a.jsxs)(n.p,{children:["The values in the packet name are separated by double underscores, e.g. ",(0,a.jsx)(n.code,{children:"<MODE>__<CMD or TLM>__<TARGET NAME>__<PACKET NAME>__<VALUE TYPE>"}),". Mode is either RAW or DECOM. The next parameter is CMD or TLM followed by the target and packet names. The Value Type is one of RAW, CONVERTED, FORMATTED, or WITH_UNITS."]}),"\n",(0,a.jsx)(n.p,{children:"For Raw mode, VALUE TYPE should be set to RAW or omitted (e.g. TLM__INST__ADCS__RAW or TLM__INST__ADCS).\nstart_time and end_time are standard COSMOS 64-bit integer timestamps in nanoseconds since the Unix Epoch (midnight January 1st, 1970). If start_time is null, that indicates to start streaming from the current time in realtime, indefinitely until items are removed, or the subscription is unsubscribed. end_time is ignored if start_time is null. If start_time is given and end_time is null, that indicates to playback from the given starttime and then continue indefinitely in realtime. If both start_time and end_time are given, then that indicates a temporary playback of historical data."}),"\n",(0,a.jsx)(n.p,{children:"Data returned by the streaming API is handled by the received callback in Javascript. Data is returned as a JSON Array, with a JSON object in the array for each packet returned. Results are batched, and the current implementation will return up to 100 packets in each batch (the array will have 100 entries). 100 packets per batch is not guaranteed, and batches may take on varying sizes based on the size of the data returned, or other factors. An empty array indicates that all data has been sent for a purely historical query and can be used as an end of data indicator."}),"\n",(0,a.jsx)(n.p,{children:"For decommutated items, each packet is represented as a JSON object with a 'time' field holding the COSMOS nanosecond timestamp of the packet, and then each of the requested item keys with their corresponding value from the packet."}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'[\n {\n "time": 1234657585858,\n "TLM__INST__ADCS__Q1__RAW": 50.0,\n "TLM__INST__ADCS__Q2__RAW": 100.0\n },\n {\n "time": 1234657585859,\n "TLM__INST__ADCS__Q1__RAW": 60.0,\n "TLM__INST__ADCS__Q2__RAW": 110.0\n }\n]\n'})}),"\n",(0,a.jsx)(n.p,{children:"For raw packets, each packet is represented as a JSON object with a time field holding the COSMOS nanosecond timestamp of the packet, a packet field holding the topic the packet was read from in the form of SCOPE__TELEMETRY__TARGETNAME__PACKETNAME, and a buffer field holding a BASE64 encoded copy of the packet data."}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'[\n {\n "time": 1234657585858,\n "packet": "DEFAULT__TELEMETRY__INST__ADCS",\n "buffer": "SkdfjGodkdfjdfoekfsg"\n },\n {\n "time": 1234657585859,\n "packet": "DEFAULT__TELEMETRY__INST__ADCS",\n "buffer": "3i5n49dmnfg9fl32k3"\n }\n]\n'})}),"\n",(0,a.jsx)(n.h2,{id:"ruby-example",children:"Ruby Example"}),"\n",(0,a.jsx)(n.p,{children:"Below is a simple Ruby example for using the streaming API to retrieve telemetry data:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-ruby",children:"require 'openc3'\nrequire 'openc3/script/web_socket_api'\n\n$openc3_scope = 'DEFAULT'\nENV['OPENC3_API_HOSTNAME'] = '127.0.0.1'\nENV['OPENC3_API_PORT'] = '2900'\nENV['OPENC3_API_PASSWORD'] = 'password'\n# The following are needed for Enterprise (change user/pass as necessary)\n#ENV['OPENC3_API_USER'] = 'operator'\n#ENV['OPENC3_API_PASSWORD'] = 'operator'\n#ENV['OPENC3_KEYCLOAK_REALM'] = 'openc3'\n#ENV['OPENC3_KEYCLOAK_URL'] = 'http://127.0.0.1:2900/auth'\n\n# Open a file to write CSV data\ncsv = File.open('telemetry_data.csv', 'w')\n\n# Connect to the streaming API\nOpenC3::StreamingWebSocketApi.new() do |api|\n # Add items to stream - request data from yesterday to 1 minute ago\n api.add(items: [\n 'DECOM__TLM__INST__HEALTH_STATUS__TEMP1__CONVERTED',\n 'DECOM__TLM__INST__HEALTH_STATUS__TEMP2__CONVERTED'\n ],\n start_time: (Time.now - 86400).to_nsec_from_epoch, # 24 hours ago\n end_time: (Time.now - 60).to_nsec_from_epoch) # 1 minute ago\n\n # Write CSV header\n csv.puts \"Time,TEMP1,TEMP2\"\n\n # Read all data from the stream\n data = api.read\n\n # Process each data point\n data.each do |item|\n csv.puts \"#{item['__time']/1_000_000_000.0},#{item['DECOM__TLM__INST__HEALTH_STATUS__TEMP1__CONVERTED']},#{item['DECOM__TLM__INST__HEALTH_STATUS__TEMP2__CONVERTED']}\"\n end\nend\ncsv.close()\n"})}),"\n",(0,a.jsx)(n.h2,{id:"streamingapi-architecture",children:"StreamingApi Architecture"}),"\n",(0,a.jsx)(n.p,{children:"The StreamingApi is a core component of COSMOS that provides real-time and historical data streaming capabilities. Below is an overview of its architecture and design."}),"\n",(0,a.jsx)(n.h3,{id:"architecture-overview",children:"Architecture Overview"}),"\n",(0,a.jsx)(n.p,{children:"The StreamingApi uses a modular architecture with several key components:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{children:"StreamingApi\n\u251C\u2500\u2500 StreamingThread (abstract)\n\u2502 \u251C\u2500\u2500 RealtimeStreamingThread\n\u2502 \u2514\u2500\u2500 LoggedStreamingThread\n\u2514\u2500\u2500 StreamingObjectCollection\n \u2514\u2500\u2500 StreamingObject\n"})}),"\n",(0,a.jsx)(n.h3,{id:"key-components",children:"Key Components"}),"\n",(0,a.jsx)(n.h4,{id:"streamingapi",children:"StreamingApi"}),"\n",(0,a.jsx)(n.p,{children:"The main class that manages streaming connections and handles client requests:"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:"Initializes with a client UUID, channel, and scope"}),"\n",(0,a.jsx)(n.li,{children:"Manages thread lifecycle for both real-time and historical data"}),"\n",(0,a.jsx)(n.li,{children:"Processes client requests to add or remove data streams"}),"\n",(0,a.jsx)(n.li,{children:"Coordinates handoff from historical to real-time streaming"}),"\n",(0,a.jsx)(n.li,{children:"Sends batched data back to clients via ActionCable"}),"\n"]}),"\n",(0,a.jsx)(n.h4,{id:"streamingthread",children:"StreamingThread"}),"\n",(0,a.jsx)(n.p,{children:"Abstract base class that defines common thread functionality:"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:"Manages thread lifecycle (start, stop)"}),"\n",(0,a.jsx)(n.li,{children:"Processes data from various sources"}),"\n",(0,a.jsx)(n.li,{children:"Handles batching and transmission of results"}),"\n",(0,a.jsx)(n.li,{children:"Determines when streaming is complete"}),"\n"]}),"\n",(0,a.jsx)(n.h4,{id:"realtimestreamingthread",children:"RealtimeStreamingThread"}),"\n",(0,a.jsx)(n.p,{children:"Specialized thread for real-time data:"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:"Subscribes to Redis topics"}),"\n",(0,a.jsx)(n.li,{children:"Processes incoming messages in real-time"}),"\n",(0,a.jsx)(n.li,{children:"Continuous streaming from current time"}),"\n"]}),"\n",(0,a.jsx)(n.h4,{id:"loggedstreamingthread",children:"LoggedStreamingThread"}),"\n",(0,a.jsx)(n.p,{children:"Specialized thread for historical data:"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:"Reads from archived log files"}),"\n",(0,a.jsx)(n.li,{children:"Handles time-based sorting of data"}),"\n",(0,a.jsx)(n.li,{children:"Transitions to real-time streaming when historical data is exhausted"}),"\n"]}),"\n",(0,a.jsx)(n.h4,{id:"streamingobject",children:"StreamingObject"}),"\n",(0,a.jsx)(n.p,{children:"Represents a single subscription item:"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:"Parses and validates stream keys"}),"\n",(0,a.jsx)(n.li,{children:"Stores metadata about the stream (mode, target, packet, item)"}),"\n",(0,a.jsx)(n.li,{children:"Tracks timestamps and offsets"}),"\n",(0,a.jsx)(n.li,{children:"Handles authorization"}),"\n"]}),"\n",(0,a.jsx)(n.h4,{id:"streamingobjectcollection",children:"StreamingObjectCollection"}),"\n",(0,a.jsx)(n.p,{children:"Manages groups of StreamingObjects:"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:"Organizes objects by topic"}),"\n",(0,a.jsx)(n.li,{children:"Tracks collective state"}),"\n",(0,a.jsx)(n.li,{children:"Provides efficient lookups"}),"\n"]}),"\n",(0,a.jsx)(n.h3,{id:"data-flow",children:"Data Flow"}),"\n",(0,a.jsxs)(n.ol,{children:["\n",(0,a.jsx)(n.li,{children:"Client connects to ActionCable and subscribes to StreamingChannel"}),"\n",(0,a.jsx)(n.li,{children:"Client sends 'add' request with items/packets to stream"}),"\n",(0,a.jsx)(n.li,{children:"StreamingApi creates appropriate StreamingObjects with authorization"}),"\n",(0,a.jsxs)(n.li,{children:["For historical requests:","\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:"LoggedStreamingThread reads from log files"}),"\n",(0,a.jsx)(n.li,{children:"Data is sent in batches to client"}),"\n",(0,a.jsx)(n.li,{children:"When historical data is exhausted, handoff to real-time"}),"\n"]}),"\n"]}),"\n",(0,a.jsxs)(n.li,{children:["For real-time requests:","\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:"RealtimeStreamingThread subscribes to Redis topics"}),"\n",(0,a.jsx)(n.li,{children:"Data is sent to client as it arrives"}),"\n"]}),"\n"]}),"\n",(0,a.jsx)(n.li,{children:"Client can add/remove items at any time"}),"\n",(0,a.jsx)(n.li,{children:"When client disconnects, all threads are terminated"}),"\n"]}),"\n",(0,a.jsx)(n.h3,{id:"performance-considerations",children:"Performance Considerations"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:"Uses thread-per-request model for historical data"}),"\n",(0,a.jsx)(n.li,{children:"Maintains a single thread for real-time data"}),"\n",(0,a.jsx)(n.li,{children:"Batches results to reduce network overhead (up to 100 items per batch)"}),"\n",(0,a.jsx)(n.li,{children:"File caching for efficient historical data access"}),"\n",(0,a.jsx)(n.li,{children:"Seamless transition from historical to real-time data"}),"\n"]}),"\n",(0,a.jsx)(n.h3,{id:"security",children:"Security"}),"\n",(0,a.jsx)(n.p,{children:"Every StreamingObject verifies authorization for the specific target and packet being requested, ensuring users only access data they have permission to view."})]})}function h(e={}){let{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,a.jsx)(n,{...e,children:(0,a.jsx)(l,{...e})}):l(e)}},5395:function(e,n,t){t.d(n,{R:()=>r,x:()=>o});var i=t(7140);let a={},s=i.createContext(a);function r(e){let n=i.useContext(s);return i.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:r(e.components),i.createElement(s.Provider,{value:n},e.children)}}}]);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";(self.webpackChunkdocs_openc3_com=self.webpackChunkdocs_openc3_com||[]).push([["2452"],{8414:function(e,a,s){s.r(a),s.d(a,{default:()=>x});var c=s(5656);s(7140);var t=s(3526),l=s(8051),n=s(8464),i=s(5752),d=s(8312),o=s(933),r=s(4856),m=s(4262);function x(e){let{content:a}=e,{metadata:s,assets:x}=a,{title:g,editUrl:p,description:h,frontMatter:j,lastUpdatedBy:A,lastUpdatedAt:_}=s,{keywords:v,wrapperClassName:u,hide_table_of_contents:f}=j,b=x.image??j.image,w=!!(p||_||A);return(0,c.jsx)(l.e3,{className:(0,t.A)(u??n.G.wrapper.mdxPages,n.G.page.mdxPage),children:(0,c.jsxs)(i.A,{children:[(0,c.jsx)(l.be,{title:g,description:h,keywords:v,image:b}),(0,c.jsx)("main",{className:"container container--fluid margin-vert--lg",children:(0,c.jsxs)("div",{className:(0,t.A)("row","mdxPageWrapper_tdJj"),children:[(0,c.jsxs)("div",{className:(0,t.A)("col",!f&&"col--8"),children:[(0,c.jsx)(r.A,{metadata:s}),(0,c.jsx)("article",{children:(0,c.jsx)(d.A,{children:(0,c.jsx)(a,{})})}),w&&(0,c.jsx)(m.A,{className:(0,t.A)("margin-top--sm",n.G.pages.pageFooterEditMetaRow),editUrl:p,lastUpdatedAt:_,lastUpdatedBy:A})]}),!f&&a.toc.length>0&&(0,c.jsx)("div",{className:"col col--2",children:(0,c.jsx)(o.A,{toc:a.toc,minHeadingLevel:j.toc_min_heading_level,maxHeadingLevel:j.toc_max_heading_level})})]})})]})})}},4578:function(e,a,s){s.d(a,{A:()=>n});var c=s(1265),t=s(5510),l=s(2726);let n={...c.A,Tabs:t.A,TabItem:l.A}}}]);
|