diff --git a/assets/js/components/tc-dynamic-values.js b/assets/js/components/tc-dynamic-values.js new file mode 100644 index 000000000..4c99171a1 --- /dev/null +++ b/assets/js/components/tc-dynamic-values.js @@ -0,0 +1,92 @@ +/** + * Highlights Telegraf Controller dynamic values in code blocks. + * + * Wraps three pattern types in styled elements: + * - Parameters: &{name} or &{name:default} + * - Environment variables: ${VAR_NAME} + * - Secrets: @{store:secret_name} + * + * Applied to code blocks with class="tc-dynamic-values" via + * the data-component="tc-dynamic-values" attribute set by + * the render-codeblock hook. + */ + +const PATTERNS = [ + { regex: /&\{[^}]+\}/g, className: 'param' }, + { regex: /\$\{[^}]+\}/g, className: 'env' }, + { regex: /@\{[^:]+:[^}]+\}/g, className: 'secret' }, +]; + +/** + * Walk all text nodes inside the given element and wrap matches + * in elements. + */ +function highlightDynamicValues(codeEl) { + const walker = document.createTreeWalker(codeEl, NodeFilter.SHOW_TEXT); + const textNodes = []; + + while (walker.nextNode()) { + textNodes.push(walker.currentNode); + } + + for (const node of textNodes) { + const text = node.textContent; + let hasMatch = false; + + for (const { regex } of PATTERNS) { + regex.lastIndex = 0; + if (regex.test(text)) { + hasMatch = true; + break; + } + } + + if (!hasMatch) continue; + + const fragment = document.createDocumentFragment(); + let remaining = text; + + while (remaining.length > 0) { + let earliestMatch = null; + let earliestIndex = remaining.length; + let matchedPattern = null; + + for (const pattern of PATTERNS) { + pattern.regex.lastIndex = 0; + const match = pattern.regex.exec(remaining); + if (match && match.index < earliestIndex) { + earliestMatch = match; + earliestIndex = match.index; + matchedPattern = pattern; + } + } + + if (!earliestMatch) { + fragment.appendChild(document.createTextNode(remaining)); + break; + } + + if (earliestIndex > 0) { + fragment.appendChild( + document.createTextNode(remaining.slice(0, earliestIndex)) + ); + } + + const span = document.createElement('span'); + span.className = `tc-dynamic-value ${matchedPattern.className}`; + span.textContent = earliestMatch[0]; + fragment.appendChild(span); + + remaining = remaining.slice(earliestIndex + earliestMatch[0].length); + } + + node.parentNode.replaceChild(fragment, node); + } +} + +export default function TcDynamicValues({ component }) { + const codeEl = component.querySelector('code'); + if (codeEl) { + highlightDynamicValues(codeEl); + } +} diff --git a/assets/js/content-interactions.js b/assets/js/content-interactions.js index eb9b4e1bc..3de1386ea 100644 --- a/assets/js/content-interactions.js +++ b/assets/js/content-interactions.js @@ -122,7 +122,7 @@ function expandAccordions() { // Expand accordions on load based on URL anchor function openAccordionByHash() { - var anchor = window.location.hash; + var anchor = window.location.hash.split('?')[0]; function expandElement() { if ($(anchor).parents('.expand').length > 0) { diff --git a/assets/js/main.js b/assets/js/main.js index 826ad9a11..866238537 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -19,6 +19,7 @@ import * as pageContext from './page-context.js'; import * as pageFeedback from './page-feedback.js'; import * as tabbedContent from './tabbed-content.js'; import * as v3Wayfinding from './v3-wayfinding.js'; +import * as tcDownloads from './tc-downloads.js'; /** Import component modules * The component pattern organizes JavaScript, CSS, and HTML for a specific UI element or interaction: @@ -44,6 +45,7 @@ import ReleaseToc from './release-toc.js'; import { SearchButton } from './search-button.js'; import SidebarSearch from './components/sidebar-search.js'; import { SidebarToggle } from './sidebar-toggle.js'; +import TcDynamicValues from './components/tc-dynamic-values.js'; import Theme from './theme.js'; import ThemeSwitch from './theme-switch.js'; @@ -75,6 +77,7 @@ const componentRegistry = { 'search-button': SearchButton, 'sidebar-search': SidebarSearch, 'sidebar-toggle': SidebarToggle, + 'tc-dynamic-values': TcDynamicValues, theme: Theme, 'theme-switch': ThemeSwitch, }; @@ -162,6 +165,7 @@ function initModules() { pageFeedback.initialize(); tabbedContent.initialize(); v3Wayfinding.initialize(); + tcDownloads.initialize(); } /** diff --git a/assets/js/tc-downloads.js b/assets/js/tc-downloads.js new file mode 100644 index 000000000..cc17837d4 --- /dev/null +++ b/assets/js/tc-downloads.js @@ -0,0 +1,221 @@ +//////////////////////////////////////////////////////////////////////////////// +///////////////// Telegraf Controller gated downloads module //////////////////// +//////////////////////////////////////////////////////////////////////////////// + +import { toggleModal } from './modals.js'; + +const STORAGE_KEY = 'influxdata_docs_tc_dl'; +const QUERY_PARAM = 'ref'; +const QUERY_VALUE = 'tc'; + +// ─── localStorage helpers ─────────────────────────────────────────────────── + +function setDownloadKey() { + localStorage.setItem(STORAGE_KEY, 'true'); +} + +function hasDownloadKey() { + return localStorage.getItem(STORAGE_KEY) === 'true'; +} + +// ─── Query param helpers ──────────────────────────────────────────────────── + +function hasRefParam() { + // Check query string first (?ref=tc before the hash) + const params = new URLSearchParams(window.location.search); + if (params.get(QUERY_PARAM) === QUERY_VALUE) return true; + + // Also check inside the fragment (#heading?ref=tc) + const hash = window.location.hash; + const qIndex = hash.indexOf('?'); + if (qIndex !== -1) { + const hashParams = new URLSearchParams(hash.substring(qIndex)); + if (hashParams.get(QUERY_PARAM) === QUERY_VALUE) return true; + } + return false; +} + +function stripRefParam() { + const url = new URL(window.location.href); + + // Remove from query string + url.searchParams.delete(QUERY_PARAM); + + // Remove from fragment if present (#heading?ref=tc → #heading) + let hash = url.hash; + const qIndex = hash.indexOf('?'); + if (qIndex !== -1) { + const hashBase = hash.substring(0, qIndex); + const hashParams = new URLSearchParams(hash.substring(qIndex)); + hashParams.delete(QUERY_PARAM); + const remaining = hashParams.toString(); + hash = remaining ? `${hashBase}?${remaining}` : hashBase; + } + + window.history.replaceState({}, '', url.pathname + url.search + hash); +} + +// ─── Download link rendering ──────────────────────────────────────────────── + +function renderDownloadLinks(container, data) { + const version = data.version; + const platforms = data.platforms; + + let html = '
'; + + platforms.forEach((platform) => { + html += `

${platform.name}

`; + html += + '

' + + `Telegraf Controller v${version}` + + '

'; + html += '
'; + + platform.builds.forEach((build) => { + const link = + `${platform.name}` + + ` (${build.arch})`; + const sha = + `sha256:${build.sha256}` + + ''; + html += + '
' + + `
${link}
` + + `
${sha}
` + + '
'; + }); + + html += '
'; + }); + + container.innerHTML = html; +} + +// ─── Clipboard copy ───────────────────────────────────────────────────────── + +function copyToClipboard(sha, button) { + if (navigator.clipboard && navigator.clipboard.writeText) { + navigator.clipboard.writeText(sha).then(() => { + showCopiedFeedback(button); + }); + } else { + // Fallback for older browsers + const textArea = document.createElement('textarea'); + textArea.value = sha; + textArea.style.position = 'fixed'; + textArea.style.opacity = '0'; + document.body.appendChild(textArea); + textArea.select(); + document.execCommand('copy'); + document.body.removeChild(textArea); + showCopiedFeedback(button); + } +} + +function showCopiedFeedback(button) { + const original = button.innerHTML; + button.innerHTML = ''; + setTimeout(() => { + button.innerHTML = original; + }, 2000); +} + +// ─── Marketo form ─────────────────────────────────────────────────────────── + +function initMarketoForm() { + /* global MktoForms2 */ + if (typeof MktoForms2 === 'undefined') { + console.error('tc-downloads: MktoForms2 not loaded'); + return; + } + + MktoForms2.setOptions({ + formXDPath: '/rs/972-GDU-533/images/marketo-xdframe-relative.html', + }); + + MktoForms2.loadForm( + 'https://get.influxdata.com', + '972-GDU-533', + 3195, + function (form) { + form.addHiddenFields({ mkto_content_name: 'Telegraf Enterprise Alpha' }); + + form.onSuccess(function () { + setDownloadKey(); + toggleModal(); + + // Redirect to self with ?ref=tc to trigger downloads on reload + const url = new URL(window.location.href); + url.searchParams.set(QUERY_PARAM, QUERY_VALUE); + window.location.href = url.toString(); + + // Prevent Marketo's default redirect + return false; + }); + } + ); +} + +// ─── View state management ────────────────────────────────────────────────── + +function showDownloads(area) { + const btn = area.querySelector('#tc-download-btn'); + const linksContainer = area.querySelector('#tc-downloads-links'); + + if (!linksContainer) return; + + // Parse download data from the JSON data attribute + const rawData = linksContainer.getAttribute('data-downloads'); + if (!rawData) return; + + let data; + try { + data = JSON.parse(atob(rawData)); + } catch (e) { + console.error('tc-downloads: failed to parse download data', e); + return; + } + + // Hide the download button + if (btn) btn.style.display = 'none'; + + // Render download links and show the container + renderDownloadLinks(linksContainer, data); + linksContainer.style.display = 'block'; +} + +// ─── Initialize ───────────────────────────────────────────────────────────── + +function initialize() { + // 1. Handle ?ref=tc query param on any page + if (hasRefParam()) { + setDownloadKey(); + stripRefParam(); + } + + const area = document.getElementById('tc-downloads-area'); + if (!area) return; // No shortcode on this page — no-op + + // 2. Check localStorage and show appropriate view + if (hasDownloadKey()) { + showDownloads(area); + } + + // 3. Initialize Marketo form + initMarketoForm(); + + // 4. Delegated click handler for SHA copy buttons + area.addEventListener('click', function (e) { + const copyBtn = e.target.closest('.tc-copy-sha'); + if (copyBtn) { + const sha = copyBtn.getAttribute('data-sha'); + if (sha) copyToClipboard(sha, copyBtn); + } + }); +} + +export { initialize }; diff --git a/assets/styles/layouts/_article.scss b/assets/styles/layouts/_article.scss index d3f56bccd..1b8584fd8 100644 --- a/assets/styles/layouts/_article.scss +++ b/assets/styles/layouts/_article.scss @@ -216,6 +216,7 @@ "article/tabbed-content", "article/tables", "article/tags", + "article/tc-downloads", "article/telegraf-plugins", "article/title", "article/truncate", diff --git a/assets/styles/layouts/_homepage.scss b/assets/styles/layouts/_homepage.scss index ca92588e9..0d321702c 100644 --- a/assets/styles/layouts/_homepage.scss +++ b/assets/styles/layouts/_homepage.scss @@ -278,8 +278,8 @@ position: relative; overflow: hidden; display: flex; - flex-direction: row; - align-items: center; + flex-direction: column; + // align-items: center; justify-content: space-between; .bg-overlay { @@ -302,9 +302,6 @@ } ul.product-links { - padding-left: 0; - margin: 0 3rem 0 2rem; - list-style: none; li:not(:last-child) {margin-bottom: .35rem;} diff --git a/assets/styles/layouts/_modals.scss b/assets/styles/layouts/_modals.scss index 2a149c378..fadb181eb 100644 --- a/assets/styles/layouts/_modals.scss +++ b/assets/styles/layouts/_modals.scss @@ -135,7 +135,8 @@ @import "modals/url-selector"; @import "modals/page-feedback"; @import "modals/flux-versions"; - @import "modals/_influxdb-gs-datepicker" + @import "modals/_influxdb-gs-datepicker"; + @import "modals/tc-downloads"; } diff --git a/assets/styles/layouts/article/_tc-downloads.scss b/assets/styles/layouts/article/_tc-downloads.scss new file mode 100644 index 000000000..a8b54d3d4 --- /dev/null +++ b/assets/styles/layouts/article/_tc-downloads.scss @@ -0,0 +1,104 @@ +/////////////////// Styles for inline TC download links //////////////////////// + +#tc-downloads-area { + margin: 0 0 2rem; + + #tc-download-btn { + display: inline-block; + } + + .tc-version { + font-size: 1rem; + color: rgba($article-text, .6); + margin-bottom: .5rem; + } + + .tc-build-table { + margin-bottom: 1rem; + } + + + .tc-build-row { + display: flex; + align-items: center; + border-bottom: 1px solid $article-hr; + + &:first-child { + border-top: 1px solid $article-hr; + } + } + + .tc-build-download { + flex: 1 1 auto; + margin-right: 1rem; + } + + .tc-download-link { + font-size: 1rem; + padding: .35rem 1rem; + white-space: nowrap; + } + + .tc-build-sha { + flex: 1 1 auto; + display: flex; + justify-content: flex-end; + gap: .1rem; + min-width: 0; + max-width: 25rem; + + code { + font-size: .8rem; + padding: .15rem .65rem; + color: $article-code; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .tc-copy-sha { + flex-shrink: 0; + background: $article-code-bg; + border: none; + border-radius: $radius; + padding: .2rem .6rem; + font-family: 'icomoon-v4'; + font-size: .9rem; + color: rgba($article-code, .85); + cursor: pointer; + transition: color .2s; + + &:hover { + color: $article-code-link-hover; + } + } + } +} + +//////////////////////////////// MEDIA QUERIES ///////////////////////////////// + +@include media(small) { + #tc-downloads-area { + .tc-build-row { + flex-direction: column; + align-items: flex-start; + gap: .5rem; + } + + .tc-build-download { + margin-right: 0; + width: 100%; + } + + .tc-download-link { + width: 100%; + text-align: center; + } + + .tc-build-sha { + width: 100%; + max-width: 100%; + margin-bottom: .5rem; + } + } +} diff --git a/assets/styles/layouts/modals/_tc-downloads.scss b/assets/styles/layouts/modals/_tc-downloads.scss new file mode 100644 index 000000000..a9def5ae8 --- /dev/null +++ b/assets/styles/layouts/modals/_tc-downloads.scss @@ -0,0 +1,226 @@ +////////////////////// Styles for the TC downloads modal //////////////////////// + +#tc-downloads { + + // ─── Reset Marketo's inline styles and defaults ──────────────────────────── + .mktoForm { + width: 100% !important; + font-family: $proxima !important; + font-size: 1rem !important; + color: $article-text !important; + padding: 0 !important; + } + + // Hide Marketo's offset/gutter spacers + .mktoOffset, + .mktoGutter { + display: none !important; + } + + // ─── Form layout: 2-column grid for first 4 fields ─────────────────────── + .mktoForm { + display: grid !important; + grid-template-columns: 1fr 1fr; + gap: 0 1.75rem; + } + + // Visible field rows (First Name, Last Name, Company, Job Title) + // occupy one grid cell each — pairs share a row automatically + .mktoFormRow { + margin-bottom: .5rem; + } + + // Hidden field rows collapse — they don't disrupt the grid + .mktoFormRow:has(input[type='hidden']) { + display: none; + } + + // Email, Privacy, and Submit span full width + .mktoFormRow:has(.mktoEmailField), + .mktoFormRow:has(.mktoCheckboxList), + .mktoButtonRow { + grid-column: 1 / -1; + } + + .mktoFieldDescriptor, + .mktoFieldWrap { + width: 100% !important; + margin-bottom: 0 !important; + } + + // ─── Labels ─────────────────────────────────────────────────────────────── + .mktoLabel { + display: flex !important; + align-items: baseline; + width: 100% !important; + font-family: $proxima !important; + font-weight: $medium !important; + font-size: .9rem !important; + color: $article-bold !important; + padding: .5rem 0 .1rem !important; + } + + .mktoAsterix { + order: 1; + color: #e85b5b !important; + float: none !important; + padding-left: .15rem; + } + + // ─── Text inputs ────────────────────────────────────────────────────────── + .mktoField.mktoTextField, + .mktoField.mktoEmailField { + width: 100% !important; + font-family: $proxima !important; + font-weight: $medium !important; + font-size: 1rem !important; + background: rgba($article-text, .06) !important; + border-radius: $radius !important; + border: 1px solid rgba($article-text, .06) !important; + padding: .5em !important; + color: $article-text !important; + transition-property: border; + transition-duration: .2s; + box-shadow: none !important; + + &:focus { + outline: none !important; + border-color: $sidebar-search-highlight !important; + } + + &::placeholder { + color: rgba($sidebar-search-text, .45) !important; + font-weight: normal !important; + font-style: italic !important; + } + } + + // ─── Checkbox / privacy consent ─────────────────────────────────────────── + .mktoFormRow:has(.mktoCheckboxList) .mktoAsterix { + display: none !important; + } + + .mktoCheckboxList { + width: 100% !important; + + label { + font-family: $proxima !important; + font-size: .85rem !important; + line-height: 1.4 !important; + color: rgba($article-text, .7) !important; + + &::after { + content: '*'; + color: #e85b5b; + font-weight: $medium; + font-size: .95rem; + font-style: normal; + } + + a { + color: $article-link !important; + font-weight: $medium; + text-decoration: none; + transition: color .2s; + + &:hover { + color: $article-link-hover !important; + } + } + } + + input[type='checkbox'] { + margin: .2rem .65rem 0 0; + } + } + + // ─── Submit button ──────────────────────────────────────────────────────── + .mktoButtonRow { + margin-top: 1rem; + display: flex; + justify-content: flex-end; + } + + .mktoButtonWrap { + margin-left: 0 !important; + } + + .mktoButton { + @include gradient($article-btn-gradient); + border: none !important; + border-radius: $radius !important; + padding: .65rem 1.5rem !important; + font-family: $proxima !important; + font-weight: $medium !important; + font-size: 1rem !important; + color: $g20-white !important; + cursor: pointer; + transition: opacity .2s; + + &:hover { + @include gradient($article-btn-gradient-hover); + } + } + + // ─── Validation errors ──────────────────────────────────────────────────── + // Marketo positions errors absolutely — make them flow inline instead + .mktoFieldWrap { + position: relative; + } + + .mktoError { + position: relative !important; + bottom: auto !important; + left: auto !important; + right: auto !important; + pointer-events: none; + + .mktoErrorArrow { + display: none !important; + } + + .mktoErrorMsg { + font-family: $proxima !important; + font-size: .8rem !important; + max-width: 100% !important; + background: none !important; + border: none !important; + color: #e85b5b !important; + padding: .15rem 0 0 !important; + box-shadow: none !important; + text-shadow: none !important; + } + } + + // ─── Custom error message ───────────────────────────────────────────────── + .tc-form-error { + margin: .75rem 0; + padding: .5rem .75rem; + background: rgba(#e85b5b, .1); + border: 1px solid rgba(#e85b5b, .3); + border-radius: $radius; + color: #e85b5b; + font-size: .9rem; + } + + // ─── Clear floats ───────────────────────────────────────────────────────── + .mktoClear { + clear: both; + } +} + +//////////////////////////////// MEDIA QUERIES ///////////////////////////////// + +@include media(small) { + #tc-downloads { + .mktoForm { + grid-template-columns: 1fr; + } + + .mktoFormRow:has(.mktoEmailField), + .mktoFormRow:has(.mktoCheckboxList), + .mktoButtonRow { + grid-column: auto; + } + } +} diff --git a/content/telegraf/controller/agents/create.md b/content/telegraf/controller/agents/create.md index 55faf4a9c..d86a9320a 100644 --- a/content/telegraf/controller/agents/create.md +++ b/content/telegraf/controller/agents/create.md @@ -41,7 +41,9 @@ The following heartbeat plugin configuration options are available: - **url**: _({{% req %}})_ URL of heartbeat endpoint. - **instance_id**: _({{% req %}})_ Unique identifier for the Telegraf instance or agent (also known as the agent ID). -- **token**: Authorization token for the heartbeat endpoint +- **token**: _({{% req text="Required with auth enabled" %}})_ + {{% product-name %}} API token for the heartbeat endpoint. + The token must have **write** permissions on the **Heartbeat** API. - **interval**: Interval for sending heartbeat messages. Default is `1m` (every minute). - **include**: Information to include in the heartbeat message. Available options are: @@ -56,12 +58,14 @@ The following heartbeat plugin configuration options are available: ### Example heartbeat output plugin The following is an example heartbeat output plugin configuration that uses -an `agent_id` [configuration parameter](#) to specify the `instance_id`. +an `agent_id` [configuration parameter](/telegraf/controller/configs/dynamic-values/#parameters) +to specify the `instance_id`. -```toml +```toml { .tc-dynamic-values } [[outputs.heartbeat]] url = "http://telegraf_controller.example.com/agents/heartbeat" instance_id = "&{agent_id}" + token = "${INFLUX_TOKEN}" interval = "1m" include = ["hostname", "statistics", "configs"] @@ -69,6 +73,17 @@ an `agent_id` [configuration parameter](#) to specify the `instance_id`. User-Agent = "telegraf" ``` +> [!Important] +> #### Authorize heartbeats using an API token +> +> If {{% product-name %}} requires authorization on the **Heartbeat** API, +> include the `token` option in your heartbeat plugin configuration. +> Provide a {{% product-name %}} token with **write** permissions on the +> **Heartbeat** API. +> +> We recommend defining the `INFLUX_TOKEN` environment variable when starting +> Telegraf and using that to define the token in your heartbeat plugin. + ## Verify a new agent 1. Open {{% product-name %}} and go to **Agents**. diff --git a/content/telegraf/controller/agents/status.md b/content/telegraf/controller/agents/status.md index eeba479f8..9c771a0ec 100644 --- a/content/telegraf/controller/agents/status.md +++ b/content/telegraf/controller/agents/status.md @@ -1,24 +1,135 @@ --- title: Set agent statuses description: > - Understand how {{% product-name %}} receives and displays agent statuses from - the heartbeat output plugin. + Configure agent status evaluation using CEL expressions in the Telegraf + heartbeat output plugin and view statuses in {{% product-name %}}. menu: telegraf_controller: name: Set agent statuses parent: Manage agents weight: 104 +related: + - /telegraf/controller/reference/agent-status-eval/, Agent status evaluation reference + - /telegraf/controller/agents/reporting-rules/ + - /telegraf/v1/output-plugins/heartbeat/, Heartbeat output plugin --- -Agent statuses come from the Telegraf heartbeat output plugin and are sent with -each heartbeat request. -The plugin reports an `ok` status. +Agent statuses reflect the health of a Telegraf instance based on runtime data. +The Telegraf [heartbeat output plugin](/telegraf/v1/output-plugins/heartbeat/) +evaluates [Common Expression Language (CEL)](/telegraf/controller/reference/agent-status-eval/) +expressions against agent metrics, error counts, and plugin statistics to +determine the status sent with each heartbeat. + + > [!Note] -> A future Telegraf release will let you configure logic that sets the status value. -{{% product-name %}} also applies reporting rules to detect stale agents. -If an agent does not send a heartbeat within the rule's threshold, Controller -marks the agent as **Not Reporting** until it resumes sending heartbeats. +> #### Requires Telegraf v1.38.0+ +> +> Agent status evaluation in the Heartbeat output plugins requires Telegraf +> v1.38.0+. + +> [!Warning] +> #### Heartbeat output plugin panic in Telegraf v1.38.0 +> +> Telegraf v1.38.0 introduced a panic in the Heartbeat output plugin that +> prevents Telegraf from starting when the plugin is enabled. Telegraf v1.38.2 +> will include a fix, but in the meantime, to use the Heartbeat output plugin, +> do one of the following: +> +> - Revert back to Telegraf v1.37.x _(Recommended)_ +> - Use a Telegraf nightly build +> - Build Telegraf from source + +## Status values + +{{% product-name %}} displays the following agent statuses: + +| Status | Source | Description | +| :---------------- | :------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| **Ok** | Heartbeat plugin | The agent is healthy. Set when the `ok` CEL expression evaluates to `true`. | +| **Warn** | Heartbeat plugin | The agent has a potential issue. Set when the `warn` CEL expression evaluates to `true`. | +| **Fail** | Heartbeat plugin | The agent has a critical problem. Set when the `fail` CEL expression evaluates to `true`. | +| **Undefined** | Heartbeat plugin | No expression matched and the `default` is set to `undefined`, or the `initial` status is `undefined`. | +| **Not Reporting** | {{% product-name %}} | The agent has not sent a heartbeat within the [reporting rule](/telegraf/controller/agents/reporting-rules/) threshold. {{% product-name %}} applies this status automatically. | + +## How status evaluation works + +You define CEL expressions for `ok`, `warn`, and `fail` in the +`[outputs.heartbeat.status]` section of your heartbeat plugin configuration. +Telegraf evaluates expressions in a configurable order and assigns the status +of the first expression that evaluates to `true`. + +For full details on evaluation flow, configuration options, and available +variables and functions, see the +[Agent status evaluation reference](/telegraf/controller/reference/agent-status-eval/). + +## Configure agent statuses + +To configure status evaluation, add `"status"` to the `include` list in your +heartbeat plugin configuration and define CEL expressions in the +`[outputs.heartbeat.status]` section. + +### Example: Basic health check + +Report `ok` when metrics are flowing. +If no metrics arrive, fall back to the `fail` status. + +```toml { .tc-dynamic-values } +[[outputs.heartbeat]] + url = "http://telegraf_controller.example.com/agents/heartbeat" + instance_id = "&{agent_id}" + token = "${INFLUX_TOKEN}" + interval = "1m" + include = ["hostname", "statistics", "configs", "logs", "status"] + + [outputs.heartbeat.status] + ok = "metrics > 0" + default = "fail" +``` + +### Example: Error-based status + +Warn when errors are logged, fail when the error count is high. + +```toml { .tc-dynamic-values } +[[outputs.heartbeat]] + url = "http://telegraf_controller.example.com/agents/heartbeat" + instance_id = "&{agent_id}" + token = "${INFLUX_TOKEN}" + interval = "1m" + include = ["hostname", "statistics", "configs", "logs", "status"] + + [outputs.heartbeat.status] + ok = "log_errors == 0 && log_warnings == 0" + warn = "log_errors > 0" + fail = "log_errors > 10" + order = ["fail", "warn", "ok"] + default = "ok" +``` + +### Example: Composite condition + +Combine error count and buffer pressure signals. + +```toml { .tc-dynamic-values } +[[outputs.heartbeat]] + url = "http://telegraf_controller.example.com/agents/heartbeat" + instance_id = "&{agent_id}" + token = "${INFLUX_TOKEN}" + interval = "1m" + include = ["hostname", "statistics", "configs", "logs", "status"] + + [outputs.heartbeat.status] + ok = "metrics > 0 && log_errors == 0" + warn = "log_errors > 0 || (has(outputs.influxdb_v2) && outputs.influxdb_v2.exists(o, o.buffer_fullness > 0.8))" + fail = "log_errors > 5 && has(outputs.influxdb_v2) && outputs.influxdb_v2.exists(o, o.buffer_fullness > 0.9)" + order = ["fail", "warn", "ok"] + default = "ok" +``` + +For more examples including buffer health, plugin-specific checks, and +time-based expressions, see +[CEL expression examples](/telegraf/controller/reference/agent-status-eval/examples/). ## View an agent's status diff --git a/content/telegraf/controller/configs/create.md b/content/telegraf/controller/configs/create.md index 3d477a9e5..c1605ce72 100644 --- a/content/telegraf/controller/configs/create.md +++ b/content/telegraf/controller/configs/create.md @@ -65,17 +65,29 @@ configuration with a [Telegraf heartbeat output plugin](/telegraf/v1/output-plug This plugin reports agent information back to the {{% product-name %}} heartbeat API and lets you monitor the health of your deployed Telegraf agents. -```toml +```toml { .tc-dynamic-values } [[outputs.heartbeat]] url = "http://localhost:8000/agents/heartbeat" instance_id = "&{agent_id}" interval = "1m" include = ["hostname", "statistics", "configs"] +token = "${INFLUX_TOKEN}" ``` To monitor agents with {{% product-name %}}, include a heartbeat plugin in your Telegraf configurations. +> [!Important] +> #### Authorize heartbeats using an API token +> +> If {{% product-name %}} requires authorization on the **Heartbeat** API, +> include the `token` option in your heartbeat plugin configuration. +> Provide a {{% product-name %}} token with **write** permissions on the +> **Heartbeat** API. +> +> We recommend defining the `INFLUX_TOKEN` environment variable when starting +> Telegraf and using that to define the token in your heartbeat plugin. + ## Next steps - Use [dynamic values](/telegraf/controller/configs/dynamic-values/) diff --git a/content/telegraf/controller/configs/dynamic-values.md b/content/telegraf/controller/configs/dynamic-values.md index 0aa27a187..0d8f939d9 100644 --- a/content/telegraf/controller/configs/dynamic-values.md +++ b/content/telegraf/controller/configs/dynamic-values.md @@ -46,8 +46,7 @@ requesting the configuration from {{% product-name %}}. ### Use parameters in Telegraf configurations -{{% telegraf/dynamic-values %}} -```toml +```toml { .tc-dynamic-values } [[outputs.influxdb_v2]] # Parameter with a default value urls = ["&{db_host:https://localhost:8181}"] @@ -56,7 +55,6 @@ requesting the configuration from {{% product-name %}}. # Required parameter without a default value instance_id = "&{agent_id}" ``` -{{% /telegraf/dynamic-values %}} The example above uses two parameters: @@ -117,15 +115,13 @@ For more information about Telegraf environment variable syntax, see ### Use environment variables in Telegraf configurations -{{% telegraf/dynamic-values %}} -```toml +```toml { .tc-dynamic-values } [[inputs.http]] urls = ["${API_ENDPOINT:-http://localhost:8080}/metrics"] [inputs.http.headers] Authorization = "Bearer ${AUTH_TOKEN}" ``` -{{% /telegraf/dynamic-values %}} The example above uses two environment variables: @@ -150,8 +146,7 @@ telegraf \ Use secrets for credentials or tokens you do not want to store in plain text. Secrets require a secret store and its corresponding `secretstores` plugin. -{{% telegraf/dynamic-values %}} -```toml +```toml { .tc-dynamic-values } # Configure a secret store plugin [[secretstores.vault]] id = "my_vault" @@ -164,7 +159,6 @@ Secrets require a secret store and its corresponding `secretstores` plugin. host = "my_influxdb.com:8181" token = "@{my_vault:influx_token}" ``` -{{% /telegraf/dynamic-values %}} For more information about Telegraf secrets and secret stores, see [Telegraf configuration options—Secret stores](/telegraf/v1/configuration/#secret-stores). diff --git a/content/telegraf/controller/configs/use.md b/content/telegraf/controller/configs/use.md index ab10dab36..3ee863896 100644 --- a/content/telegraf/controller/configs/use.md +++ b/content/telegraf/controller/configs/use.md @@ -40,6 +40,24 @@ telegraf \ Telegraf retrieves and validates the configuration from {{% product-name %}} and then starts the `telegraf` process using the loaded configuration. +### Retrieve a configuration with authorization enabled + +If {{% product-name %}} is configured to require authentication on the **Configs** +API, define the `INFLUX_TOKEN` environment variable to authorize Telegraf +to retrieve a configuration: + + +```bash { placeholders="YOUR_TC_API_TOKEN" } +export INFLUX_TOKEN=YOUR_TC_API_TOKEN + +telegraf \ + --config "http://telegraf_controller.example.com/api/configs/xxxxxx/toml +``` + +Replace {{% code-placeholder-key %}}`YOUR_TC_API_TOKEN`{{% /code-placeholder-key %}} +with your {{% product-name %}} API token. This token must have **read** +permissions on the **Configs** API. + ## Set dynamic values Telegraf and {{% product-name %}} let you @@ -58,13 +76,11 @@ values—for example: ##### Configuration TOML with a parameter -{{% telegraf/dynamic-values %}} -```toml +```toml { .tc-dynamic-values } [[outputs.heartbeat]] instance_id = "&{agent_id}" # ... ``` -{{% /telegraf/dynamic-values %}} ##### Set the parameter value in the configuration URL @@ -88,15 +104,13 @@ starting Telegraf—for example: ##### Configuration TOML with an environment variable -{{% telegraf/dynamic-values %}} -```toml +```toml { .tc-dynamic-values } [[inputs.http]] urls = ["http://localhost:8080/metrics"] [inputs.http.headers] Authorization = "Bearer ${AUTH_TOKEN}" ``` -{{% /telegraf/dynamic-values %}} ##### Set the environment variable before starting Telegraf @@ -135,21 +149,50 @@ parameters, environment variables, auto-update functionality, and Telegraf {{< img-hd src="/img/telegraf/controller-command-builder.png" alt="Build Telegraf commands with Telegraf Controller" />}} -4. Define dynamic values and select options for your command: +4. _Optional_: To download a configuration and run it from your local filesystem + rather than having Telegraf retrieve it directly from {{% product-name %}}, + enable the **Use local configuration file** option. + See more information [below](#download-a-configuration-to-your-local-filesystem). + +5. Define dynamic values and select options for your command: - Set environment variable values - Set parameter values - Enable automatic configuration updates and specify the check interval - Add label selectors to run certain plugins based on configuration labels -5. Click **Copy Commands** to copy the contents of the codeblock to your clipboard. +6. Click **Copy Commands** to copy the contents of the codeblock to your clipboard. The tool provides commands for Linux, macOS, and Windows (PowerShell). > [!Warning] + > #### Some browsers restrict copying to clipboard + > > Your browser may not allow the **Copy Commands** button to copy to your > clipboard under the following conditions: > > - You're using an IP or domain name other than `0.0.0.0` or `localhost` and > - You're using HTTP, not HTTPS - +### Download a configuration to your local filesystem + +With the **Use local configuration file** option enabled in the command builder, +{{% product-name %}} lets you configure the directory path and file name to use +for the configuration. + +1. Define dynamic values and select options for your command: + + - Set file details + - Set environment variable values + - Set parameter values + - Enable automatic configuration updates and specify the check strategy + - Add label selectors to run certain plugins based on configuration labels + +2. Click **Download Config** to download the configuration to your local machine. + The downloaded TOML files uses the file name specified in the + **File Details** tab and includes all the specified parameter replacements. + +3. Click **Copy Commands** to copy the contents of the codeblock to your clipboard. + The tool provides commands for Linux, macOS, and Windows (PowerShell). + See [information about copying to your clipboard](#some-browsers-restrict-copying-to-clipboard). + +{{< img-hd src="/img/telegraf/controller-command-builder-dl.png" alt="Telegraf Controller command builder" />}} diff --git a/content/telegraf/controller/install/_index.md b/content/telegraf/controller/install/_index.md index ad70134ea..e2f6cd6fb 100644 --- a/content/telegraf/controller/install/_index.md +++ b/content/telegraf/controller/install/_index.md @@ -18,6 +18,7 @@ configurations, monitoring agents, and organizing plugins. - [Download and install {{% product-name %}}](#download-and-install-telegraf-controller) - [Set up your database](#set-up-your-database) - [Configure {{% product-name %}}](#configure-telegraf-controller) +- [Set up the owner account](#set-up-the-owner-account) - [Access {{% product-name %}}](#access-telegraf-controller) ## System Requirements @@ -75,15 +76,7 @@ $env:TELEGRAF_CONTROLLER_EULA="accept" 1. **Download the {{% product-name %}} executable.** - > [!Note] - > #### Contact InfluxData for download - > - > If you are currently participating in the {{% product-name %}} private alpha, - > send your operating system and architecture to InfluxData and we will - > provide you with the appropriate {{% product-name %}} executable. - > - > If you are not currently in the private alpha and would like to be, - > [request early access](https://www.influxdata.com/products/telegraf-enterprise). + {{< telegraf/tc-downloads >}} 2. **Install {{% product-name %}}**. @@ -508,6 +501,93 @@ $env:TELEGRAF_CONTROLLER_EULA=accept {{% /tab-content %}} {{< /tabs-wrapper >}} +## Set up the owner account + +The first time you access {{% product-name %}}, you need to create an owner account. +The owner has full administrative access to the application, including the +ability to manage users, configurations, and agents. + +You can create the owner account using one of four methods: + +- [Interactive CLI setup](#interactive-cli-setup) when starting the application +- [Environment variables](#environment-variable-setup) set before starting the application +- [Command line flags](#command-line-flag-setup) passed when starting the application +- [Web interface setup](#web-interface-setup) after starting the application + +### Interactive CLI setup + +When you start {{% product-name %}} in interactive mode (default) and no owner +account exists, {{% product-name %}} prompts you to provide owner username, +email address, and password. + +### Environment variable setup + +You can configure the owner account by setting environment variables before +starting {{% product-name %}}. +This method is useful for automated deployments and containerized environments. + +| Environment variable | Description | +| :------------------- | :------------------ | +| `OWNER_EMAIL` | Owner email address | +| `OWNER_USERNAME` | Owner username | +| `OWNER_PASSWORD` | Owner password | + +Set all three environment variables and then start the application: + +```bash +export OWNER_EMAIL="admin@example.com" +export OWNER_USERNAME="admin" +export OWNER_PASSWORD="secure-password-here" + +./telegraf-controller +``` + +> [!Note] +> If an owner account already exists, {{% product-name %}} ignores these +> environment variables. + +> [!Important] +> If an administrator account already exists with the specified username, +> that account is promoted to owner. + +### Command line flag setup + +You can also pass owner account details as command line flags when starting +{{% product-name %}}. + +| Flag | Description | +|:-------------------------|:-----------------------| +| `--owner-email=EMAIL` | Owner email address | +| `--owner-username=NAME` | Owner username | +| `--owner-password=PASS` | Owner password | + +Pass all three flags when starting the application: + +```bash +./telegraf-controller \ + --owner-email="admin@example.com" \ + --owner-username="admin" \ + --owner-password="secure-password-here" +``` + +> [!Tip] +> Command line flags take precedence over environment variables. +> If you set both, {{% product-name %}} uses the values from the command line flags. + +### Web interface setup + +If no owner account exists when you start {{% product-name %}} in non-interactive +mode, the web interface displays a setup page where you can create one. + +1. Navigate to the [{{% product-name %}} URL](#access-telegraf-controller) in your browser. +2. Fill in the **Username**, **Email**, and **Password** fields. +3. Click **Create Account**. + +{{< img-hd src="/img/telegraf/controller-setup-owner-account.png" alt="Owner account setup page" />}} + +For more information about user roles and permissions, see +[Authorization](/telegraf/controller/reference/authorization/). + ## Access {{% product-name %}} Once started, access the {{% product-name %}} web interface at diff --git a/content/telegraf/controller/reference/agent-status-eval/_index.md b/content/telegraf/controller/reference/agent-status-eval/_index.md new file mode 100644 index 000000000..bef40c47f --- /dev/null +++ b/content/telegraf/controller/reference/agent-status-eval/_index.md @@ -0,0 +1,97 @@ +--- +title: Agent status evaluation +description: > + Reference documentation for Common Expression Language (CEL) expressions used + to evaluate Telegraf agent status. +menu: + telegraf_controller: + name: Agent status evaluation + parent: Reference +weight: 107 +related: + - /telegraf/controller/agents/status/ + - /telegraf/v1/output-plugins/heartbeat/ +--- + +The Telegraf [heartbeat output plugin](/telegraf/v1/output-plugins/heartbeat/) +uses CEL expressions to evaluate agent status based on runtime data such as +metric counts, error rates, and plugin statistics. +[CEL (Common Expression Language)](https://cel.dev) is a lightweight expression +language designed for evaluating simple conditions. + +## How status evaluation works + +You define CEL expressions for three status levels in the +`[outputs.heartbeat.status]` section of your Telegraf configuration: + +- **ok** — The agent is healthy. +- **warn** — The agent has a potential issue. +- **fail** — The agent has a critical problem. + +Each expression is a CEL program that returns a boolean value. +Telegraf evaluates expressions in a configurable order (default: +`ok`, `warn`, `fail`) and assigns the status of the **first expression that +evaluates to `true`**. + +If no expression evaluates to `true`, the `default` status is used +(default: `"ok"`). + +### Initial status + +Use the `initial` setting to define a status before the first Telegraf flush +cycle. +If `initial` is not set or is empty, Telegraf evaluates the status expressions +immediately, even before the first flush. + +### Evaluation order + +The `order` setting controls which expressions are evaluated and in what +sequence. + +> [!Note] +> If you omit a status from the `order` list, its expression is **not +> evaluated**. + +## Configuration reference + +Configure status evaluation in the `[outputs.heartbeat.status]` section of the +heartbeat output plugin. +You must include `"status"` in the `include` list for status evaluation to take +effect. + +```toml +[[outputs.heartbeat]] + url = "http://telegraf_controller.example.com/agents/heartbeat" + instance_id = "agent-123" + interval = "1m" + include = ["hostname", "statistics", "status"] + + [outputs.heartbeat.status] + ## CEL expressions that return a boolean. + ## The first expression that evaluates to true sets the status. + ok = "metrics > 0" + warn = "log_errors > 0" + fail = "log_errors > 10" + + ## Evaluation order (default: ["ok", "warn", "fail"]) + order = ["ok", "warn", "fail"] + + ## Default status when no expression matches + ## Options: "ok", "warn", "fail", "undefined" + default = "ok" + + ## Initial status before the first flush cycle + ## Options: "ok", "warn", "fail", "undefined", "" + # initial = "" +``` + +| Option | Type | Default | Description | +|:-------|:-----|:--------|:------------| +| `ok` | string (CEL) | `"false"` | Expression that, when `true`, sets status to **ok**. | +| `warn` | string (CEL) | `"false"` | Expression that, when `true`, sets status to **warn**. | +| `fail` | string (CEL) | `"false"` | Expression that, when `true`, sets status to **fail**. | +| `order` | list of strings | `["ok", "warn", "fail"]` | Order in which expressions are evaluated. | +| `default` | string | `"ok"` | Status used when no expression evaluates to `true`. Options: `ok`, `warn`, `fail`, `undefined`. | +| `initial` | string | `""` | Status before the first flush. Options: `ok`, `warn`, `fail`, `undefined`, `""` (empty = evaluate expressions). | + +{{< children hlevel="h2" >}} diff --git a/content/telegraf/controller/reference/agent-status-eval/examples.md b/content/telegraf/controller/reference/agent-status-eval/examples.md new file mode 100644 index 000000000..355eb2764 --- /dev/null +++ b/content/telegraf/controller/reference/agent-status-eval/examples.md @@ -0,0 +1,257 @@ +--- +title: CEL expression examples +description: > + Real-world examples of CEL expressions for evaluating Telegraf agent status. +menu: + telegraf_controller: + name: Examples + parent: Agent status evaluation +weight: 203 +related: + - /telegraf/controller/agents/status/ + - /telegraf/controller/reference/agent-status-eval/variables/ + - /telegraf/controller/reference/agent-status-eval/functions/ +--- + +Each example includes a scenario description, the CEL expression, a full +heartbeat plugin configuration block, and an explanation. + +For the full list of available variables and functions, see: + +- [CEL variables](/telegraf/controller/reference/agent-status-eval/variables/) +- [CEL functions and operators](/telegraf/controller/reference/agent-status-eval/functions/) + +## Basic health check + +**Scenario:** Report `ok` when Telegraf is actively processing metrics. +Fall back to the default status (`ok`) when no expression matches — this means +the agent is healthy as long as metrics are flowing. + +**Expression:** + +```js +ok = "metrics > 0" +``` + +**Configuration:** + +```toml +[[outputs.heartbeat]] + url = "http://telegraf_controller.example.com/agents/heartbeat" + instance_id = "agent-123" + interval = "1m" + include = ["hostname", "statistics", "configs", "logs", "status"] + + [outputs.heartbeat.status] + ok = "metrics > 0" + default = "fail" +``` + +**How it works:** If the heartbeat plugin received metrics since the last +heartbeat, the status is `ok`. +If no metrics arrived, no expression matches and the `default` status of `fail` +is used, indicating the agent is not processing data. + +## Error rate monitoring + +**Scenario:** Warn when any errors are logged and fail when the error count is +high. + +**Expressions:** + +```js +warn = "log_errors > 0" +fail = "log_errors > 10" +``` + +**Configuration:** + +```toml +[[outputs.heartbeat]] + url = "http://telegraf_controller.example.com/agents/heartbeat" + instance_id = "agent-123" + interval = "1m" + include = ["hostname", "statistics", "configs", "logs", "status"] + + [outputs.heartbeat.status] + ok = "log_errors == 0 && log_warnings == 0" + warn = "log_errors > 0" + fail = "log_errors > 10" + order = ["fail", "warn", "ok"] + default = "ok" +``` + +**How it works:** Expressions are evaluated in `fail`, `warn`, `ok` order. +If more than 10 errors occurred since the last heartbeat, the status is `fail`. +If 1-10 errors occurred, the status is `warn`. +If no errors or warnings occurred, the status is `ok`. + +## Buffer health + +**Scenario:** Warn when any output plugin's buffer exceeds 80% fullness, +indicating potential data backpressure. + +**Expression:** + +```js +warn = "outputs.influxdb_v2.exists(o, o.buffer_fullness > 0.8)" +fail = "outputs.influxdb_v2.exists(o, o.buffer_fullness > 0.95)" +``` + +**Configuration:** + +```toml +[[outputs.heartbeat]] + url = "http://telegraf_controller.example.com/agents/heartbeat" + instance_id = "agent-123" + interval = "1m" + include = ["hostname", "statistics", "configs", "logs", "status"] + + [outputs.heartbeat.status] + ok = "metrics > 0" + warn = "outputs.influxdb_v2.exists(o, o.buffer_fullness > 0.8)" + fail = "outputs.influxdb_v2.exists(o, o.buffer_fullness > 0.95)" + order = ["fail", "warn", "ok"] + default = "ok" +``` + +**How it works:** The `outputs.influxdb_v2` map contains a list of all +`influxdb_v2` output plugin instances. +The `exists()` function iterates over all instances and returns `true` if any +instance's `buffer_fullness` exceeds the threshold. +At 95% fullness, the status is `fail`; at 80%, `warn`; otherwise `ok`. + +## Plugin-specific checks + +**Scenario:** Monitor a specific input plugin for collection errors and use +safe access patterns to avoid errors when the plugin is not configured. + +**Expression:** + +```js +warn = "has(inputs.cpu) && inputs.cpu.exists(i, i.errors > 0)" +fail = "has(inputs.cpu) && inputs.cpu.exists(i, i.startup_errors > 0)" +``` + +**Configuration:** + +```toml +[[outputs.heartbeat]] + url = "http://telegraf_controller.example.com/agents/heartbeat" + instance_id = "agent-123" + interval = "1m" + include = ["hostname", "statistics", "configs", "logs", "status"] + + [outputs.heartbeat.status] + ok = "metrics > 0" + warn = "has(inputs.cpu) && inputs.cpu.exists(i, i.errors > 0)" + fail = "has(inputs.cpu) && inputs.cpu.exists(i, i.startup_errors > 0)" + order = ["fail", "warn", "ok"] + default = "ok" +``` + +**How it works:** The `has()` function checks if the `cpu` key exists in the +`inputs` map before attempting to access it. +This prevents evaluation errors when the plugin is not configured. +If the plugin has startup errors, the status is `fail`. +If it has collection errors, the status is `warn`. + +## Composite conditions + +**Scenario:** Combine multiple signals to detect a degraded agent — high error +count combined with output buffer pressure. + +**Expression:** + +```js +fail = "log_errors > 5 && has(outputs.influxdb_v2) && outputs.influxdb_v2.exists(o, o.buffer_fullness > 0.9)" +``` + +**Configuration:** + +```toml +[[outputs.heartbeat]] + url = "http://telegraf_controller.example.com/agents/heartbeat" + instance_id = "agent-123" + interval = "1m" + include = ["hostname", "statistics", "configs", "logs", "status"] + + [outputs.heartbeat.status] + ok = "metrics > 0 && log_errors == 0" + warn = "log_errors > 0 || (has(outputs.influxdb_v2) && outputs.influxdb_v2.exists(o, o.buffer_fullness > 0.8))" + fail = "log_errors > 5 && has(outputs.influxdb_v2) && outputs.influxdb_v2.exists(o, o.buffer_fullness > 0.9)" + order = ["fail", "warn", "ok"] + default = "ok" +``` + +**How it works:** The `fail` expression requires **both** a high error count +**and** buffer pressure to trigger. +The `warn` expression uses `||` to trigger on **either** condition independently. +This layered approach avoids false alarms from transient spikes in a single +metric. + +## Time-based expressions + +**Scenario:** Warn when the time since the last successful heartbeat exceeds a +threshold, indicating potential connectivity or performance issues. + +**Expression:** + +```js +warn = "now() - last_update > duration('10m')" +fail = "now() - last_update > duration('30m')" +``` + +**Configuration:** + +```toml +[[outputs.heartbeat]] + url = "http://telegraf_controller.example.com/agents/heartbeat" + instance_id = "agent-123" + interval = "1m" + include = ["hostname", "statistics", "configs", "logs", "status"] + + [outputs.heartbeat.status] + ok = "metrics > 0" + warn = "now() - last_update > duration('10m')" + fail = "now() - last_update > duration('30m')" + order = ["fail", "warn", "ok"] + default = "undefined" + initial = "undefined" +``` + +**How it works:** The `now()` function returns the current time and +`last_update` is the timestamp of the last successful heartbeat. +Subtracting them produces a duration that can be compared against a threshold. +The `initial` status is set to `undefined` so new agents don't immediately show +a stale-data warning before their first successful heartbeat. + +## Custom evaluation order + +**Scenario:** Use fail-first evaluation to prioritize detecting critical issues +before checking for healthy status. + +**Configuration:** + +```toml +[[outputs.heartbeat]] + url = "http://telegraf_controller.example.com/agents/heartbeat" + instance_id = "agent-123" + interval = "1m" + include = ["hostname", "statistics", "configs", "logs", "status"] + + [outputs.heartbeat.status] + ok = "metrics > 0 && log_errors == 0" + warn = "log_errors > 0" + fail = "log_errors > 10 || agent.metrics_dropped > 100" + order = ["fail", "warn", "ok"] + default = "undefined" +``` + +**How it works:** By setting `order = ["fail", "warn", "ok"]`, the most severe +conditions are checked first. +If the agent has more than 10 logged errors or has dropped more than 100 +metrics, the status is `fail` — regardless of whether the `ok` or `warn` +expression would also match. +This is the recommended order for production deployments where early detection +of critical issues is important. diff --git a/content/telegraf/controller/reference/agent-status-eval/functions.md b/content/telegraf/controller/reference/agent-status-eval/functions.md new file mode 100644 index 000000000..c5bfcf112 --- /dev/null +++ b/content/telegraf/controller/reference/agent-status-eval/functions.md @@ -0,0 +1,120 @@ +--- +title: CEL functions and operators +description: > + Reference for functions and operators available in CEL expressions used to + evaluate Telegraf agent status. +menu: + telegraf_controller: + name: Functions + parent: Agent status evaluation +weight: 202 +--- + +CEL expressions for agent status evaluation support built-in CEL operators and +the following function libraries. + +## Time functions + +### `now()` + +Returns the current time. +Use with `last_update` to calculate durations or detect stale data. + +```js +// True if more than 10 minutes since last heartbeat +now() - last_update > duration('10m') +``` + +```js +// True if more than 5 minutes since last heartbeat +now() - last_update > duration('5m') +``` + +## Math functions + +Math functions from the +[CEL math library](https://github.com/google/cel-go/blob/master/ext/README.md#math) +are available for numeric calculations. + +### Commonly used functions + +| Function | Description | Example | +|:---------|:------------|:--------| +| `math.greatest(a, b, ...)` | Returns the greatest value. | `math.greatest(log_errors, log_warnings)` | +| `math.least(a, b, ...)` | Returns the least value. | `math.least(agent.metrics_gathered, 1000)` | + +### Example + +```js +// Warn if either errors or warnings exceed a threshold +math.greatest(log_errors, log_warnings) > 5 +``` + +## String functions + +String functions from the +[CEL strings library](https://github.com/google/cel-go/blob/master/ext/README.md#strings) +are available for string operations. +These are useful when checking plugin `alias` or `id` fields. + +### Example + +```js +// Check if any input plugin has an alias containing "critical" +inputs.cpu.exists(i, has(i.alias) && i.alias.contains("critical")) +``` + +## Encoding functions + +Encoding functions from the +[CEL encoder library](https://github.com/google/cel-go/blob/master/ext/README.md#encoders) +are available for encoding and decoding values. + +## Operators + +CEL supports standard operators for building expressions. + +### Comparison operators + +| Operator | Description | Example | +|:---------|:------------|:--------| +| `==` | Equal | `metrics == 0` | +| `!=` | Not equal | `log_errors != 0` | +| `<` | Less than | `agent.metrics_gathered < 100` | +| `<=` | Less than or equal | `buffer_fullness <= 0.5` | +| `>` | Greater than | `log_errors > 10` | +| `>=` | Greater than or equal | `metrics >= 1000` | + +### Logical operators + +| Operator | Description | Example | +|:---------|:------------|:--------| +| `&&` | Logical AND | `log_errors > 0 && metrics == 0` | +| `\|\|` | Logical OR | `log_errors > 10 \|\| log_warnings > 50` | +| `!` | Logical NOT | `!(metrics > 0)` | + +### Arithmetic operators + +| Operator | Description | Example | +|:---------|:------------|:--------| +| `+` | Addition | `log_errors + log_warnings` | +| `-` | Subtraction | `agent.metrics_gathered - agent.metrics_dropped` | +| `*` | Multiplication | `log_errors * 2` | +| `/` | Division | `agent.metrics_dropped / agent.metrics_gathered` | +| `%` | Modulo | `metrics % 100` | + +### Ternary operator + +```js +// Conditional expression +log_errors > 10 ? true : false +``` + +### List operations + +| Function | Description | Example | +|:---------|:------------|:--------| +| `exists(var, condition)` | True if any element matches. | `inputs.cpu.exists(i, i.errors > 0)` | +| `all(var, condition)` | True if all elements match. | `outputs.influxdb_v2.all(o, o.errors == 0)` | +| `size()` | Number of elements. | `inputs.cpu.size() > 0` | +| `has()` | True if a field or key exists. | `has(inputs.cpu)` | diff --git a/content/telegraf/controller/reference/agent-status-eval/variables.md b/content/telegraf/controller/reference/agent-status-eval/variables.md new file mode 100644 index 000000000..8861d2126 --- /dev/null +++ b/content/telegraf/controller/reference/agent-status-eval/variables.md @@ -0,0 +1,150 @@ +--- +title: CEL variables +description: > + Reference for variables available in CEL expressions used to evaluate + Telegraf agent status in {{% product-name %}}. +menu: + telegraf_controller: + name: Variables + parent: Agent status evaluation +weight: 201 +--- + +CEL expressions for agent status evaluation have access to variables that +represent data collected by Telegraf since the last successful heartbeat message +(unless noted otherwise). + +## Top-level variables + +| Variable | Type | Description | +| :------------- | :--- | :---------------------------------------------------------------------------------------------------- | +| `metrics` | int | Number of metrics arriving at the heartbeat output plugin. | +| `log_errors` | int | Number of errors logged by the Telegraf instance. | +| `log_warnings` | int | Number of warnings logged by the Telegraf instance. | +| `last_update` | time | Timestamp of the last successful heartbeat message. Use with `now()` to calculate durations or rates. | +| `agent` | map | Agent-level statistics. See [Agent statistics](#agent-statistics). | +| `inputs` | map | Input plugin statistics. See [Input plugin statistics](#input-plugin-statistics-inputs). | +| `outputs` | map | Output plugin statistics. See [Output plugin statistics](#output-plugin-statistics-outputs). | + +## Agent statistics + +The `agent` variable is a map containing aggregate statistics for the entire +Telegraf instance. +These fields correspond to the `internal_agent` metric from the +Telegraf [internal input plugin](/telegraf/v1/plugins/#input-internal). + +| Field | Type | Description | +| :----------------------- | :--- | :-------------------------------------------------- | +| `agent.metrics_written` | int | Total metrics written by all output plugins. | +| `agent.metrics_rejected` | int | Total metrics rejected by all output plugins. | +| `agent.metrics_dropped` | int | Total metrics dropped by all output plugins. | +| `agent.metrics_gathered` | int | Total metrics collected by all input plugins. | +| `agent.gather_errors` | int | Total collection errors across all input plugins. | +| `agent.gather_timeouts` | int | Total collection timeouts across all input plugins. | + +### Example + +```js +agent.gather_errors > 0 +``` + +## Input plugin statistics (`inputs`) + +The `inputs` variable is a map where each key is a plugin type (for example, +`cpu` for `inputs.cpu`) and the value is a **list** of plugin instances. +Each entry in the list represents one configured instance of that plugin type. + +These fields correspond to the `internal_gather` metric from the Telegraf +[internal input plugin](/telegraf/v1/plugins/#input-internal). + +| Field | Type | Description | +| :----------------- | :----- | :---------------------------------------------------------------------------------------- | +| `id` | string | Unique plugin identifier. | +| `alias` | string | Alias set for the plugin. Only exists if an alias is defined in the plugin configuration. | +| `errors` | int | Collection errors for this plugin instance. | +| `metrics_gathered` | int | Number of metrics collected by this instance. | +| `gather_time_ns` | int | Time spent gathering metrics, in nanoseconds. | +| `gather_timeouts` | int | Number of timeouts during metric collection. | +| `startup_errors` | int | Number of times the plugin failed to start. | + +### Access patterns + +Access a specific plugin type and iterate over its instances: + +```js +// Check if any cpu input instance has errors +inputs.cpu.exists(i, i.errors > 0) +``` + +```js +// Access the first instance of the cpu input +inputs.cpu[0].metrics_gathered +``` + +Use `has()` to safely check if a plugin type exists before accessing it: + +```js +// Safe access — returns false if no cpu input is configured +has(inputs.cpu) && inputs.cpu.exists(i, i.errors > 0) +``` + +## Output plugin statistics (`outputs`) + +The `outputs` variable is a map with the same structure as `inputs`. +Each key is a plugin type (for example, `influxdb_v3` for `outputs.influxdb_v3`) +and the value is a list of plugin instances. + +These fields correspond to the `internal_write` metric from the Telegraf +[internal input plugin](/telegraf/v1/plugins/#input-internal). + +| Field | Type | Description | +| :----------------- | :----- | :------------------------------------------------------------------------------------------------------- | +| `id` | string | Unique plugin identifier. | +| `alias` | string | Alias set for the plugin. Only exists if an alias is defined in the plugin configuration. | +| `errors` | int | Write errors for this plugin instance. | +| `metrics_filtered` | int | Number of metrics filtered by the output. | +| `write_time_ns` | int | Time spent writing metrics, in nanoseconds. | +| `startup_errors` | int | Number of times the plugin failed to start. | +| `metrics_added` | int | Number of metrics added to the output buffer. | +| `metrics_written` | int | Number of metrics written to the output destination. | +| `metrics_rejected` | int | Number of metrics rejected by the service or serialization. | +| `metrics_dropped` | int | Number of metrics dropped (for example, due to buffer fullness). | +| `buffer_size` | int | Current number of metrics in the output buffer. | +| `buffer_limit` | int | Capacity of the output buffer. Irrelevant for disk-based buffers. | +| `buffer_fullness` | float | Ratio of metrics in the buffer to capacity. Can exceed `1.0` (greater than 100%) for disk-based buffers. | + +### Access patterns + +```js +// Access the first instance of the InfluxDB v3 output plugin +outputs.influxdb_v3[0].metrics_written +``` + +```js +// Check if any InfluxDB v3 output has write errors +outputs.influxdb_v3.exists(o, o.errors > 0) +``` + +```js +// Check buffer fullness across all instances of an output +outputs.influxdb_v3.exists(o, o.buffer_fullness > 0.8) +``` + +Use `has()` to safely check if a plugin type exists before accessing it: + +```js +// Safe access — returns false if no cpu input is configured +has(outputs.influxdb_v3) && outputs.influxdb_v3.exists(o, o.errors > 0) +``` + +## Accumulation behavior + +Unless noted otherwise, all variable values are **accumulated since the last +successful heartbeat message**. +Use the `last_update` variable with `now()` to calculate rates — for example: + +```js +// True if the error rate exceeds 1 error per minute +log_errors > 0 && duration.getMinutes(now() - last_update) > 0 + && log_errors / duration.getMinutes(now() - last_update) > 1 +``` diff --git a/content/telegraf/controller/reference/authorization.md b/content/telegraf/controller/reference/authorization.md new file mode 100644 index 000000000..48708f6c2 --- /dev/null +++ b/content/telegraf/controller/reference/authorization.md @@ -0,0 +1,79 @@ +--- +title: Authorization +description: > + Understand how authentication and authorization work in Telegraf Controller, + including user roles, API tokens, and endpoint security. +menu: + telegraf_controller: + name: Authorization + parent: Reference +weight: 106 +related: + - /telegraf/controller/users/ + - /telegraf/controller/tokens/ + - /telegraf/controller/settings/ +--- + +{{% product-name %}} uses session-based authentication for the web UI and +token-based authentication for API and Telegraf agent requests. +Both mechanisms work together to control who can access the system and what +actions they can perform. + +## User roles + +{{% product-name %}} enforces a four-tier role hierarchy. +Each role inherits the permissions of the roles below it, and higher roles +unlock additional administrative capabilities. + +| Role | Description | +| :-------------- | :------------------------------------------------------------------------------------------------------------------- | +| **Owner** | Full system access. Manages users, tokens, and settings. Only one owner exists at a time. Created during initial setup. | +| **Administrator** | Full system access. Same capabilities as the owner except cannot transfer ownership. | +| **Manager** | Manages configurations, agents, labels, and reporting rules. Manages own API tokens. Cannot manage users or settings. | +| **Viewer** | Read-only access to configurations, agents, labels, and reporting rules. Cannot manage tokens, users, or settings. | + +Only one owner can exist at a time. +The owner account is created during initial setup and cannot be deleted. +If you need to change the owner, the current owner must transfer ownership to +another user. + +> [!Tip] +> To change the owner of your {{% product-name %}} instance, see [Transfer ownership](/telegraf/controller/users/transfer-ownership/). + +## API tokens + +API tokens authenticate programmatic API requests and Telegraf agent connections +to {{% product-name %}}. + +Each token is scoped to the user who created it. +The token's effective permissions are restricted to the creating user's role---a +token cannot exceed the permissions of its owner. +If a user's role changes to a role with less permissions, all of that user's +existing tokens are automatically updated with restricted permissions or revoked +to match the new role. + +Tokens use the `tc-apiv1_` prefix, making them easy to identify in configuration +files and scripts. + +> [!Important] +> A token value is shown only once at the time of creation. +> Store it in a secure location immediately---you cannot retrieve it later. + +## Endpoint authentication + +By default, {{% product-name %}} requires authentication for API endpoints. +Administrators can selectively require authentication for individual endpoint +groups: + +- **Agents** --- agent management endpoints +- **Configs** --- configuration management endpoints +- **Labels** --- label management endpoints +- **Reporting rules** --- reporting rule management endpoints +- **Heartbeat** --- agent heartbeat endpoints + +When authentication is enabled for an endpoint group, every request to that +group must include a valid API token or an active session. + +> [!Note] +> To configure which endpoint groups require authentication, see +> [Manage settings](/telegraf/controller/settings/). diff --git a/content/telegraf/controller/reference/release-notes.md b/content/telegraf/controller/reference/release-notes.md new file mode 100644 index 000000000..8b24141a8 --- /dev/null +++ b/content/telegraf/controller/reference/release-notes.md @@ -0,0 +1,217 @@ +--- +title: Telegraf Controller release notes +description: > + Important features, bug fixes, and changes in Telegraf Controller releases. +menu: + telegraf_controller: + name: Release notes + parent: Reference +weight: 101 +--- + +## v0.0.5-beta {date="2026-03-26"} + + +[Download Telegraf Controller v0.0.5-beta](/telegraf/controller/install/#download-and-install-telegraf-controller) + +### Important changes + +This release introduces user and account management, API token authentication, +and configurable authentication options. +By default, authentication is required to interact with all API endpoints. +If you have agents reading configurations from and reporting heartbeats +to {{% product-name %}}, they will begin to fail with authorization errors. + +**To avoid agent authorization errors:** + +1. Temporarily disable authentication on the **Heartbeat** and **Configs** APIs. + You can use either the `--disable-auth-endpoints` command flag or the + `DISABLED_AUTH_ENDPOINTS` environment variable when starting + {{% product-name %}}. + + {{< code-tabs-wrapper >}} +{{% code-tabs %}} +[Command flags](#) +[Environment Variables](#) +{{% /code-tabs %}} +{{% code-tab-content %}} + + +```bash +telegraf_controller --disable-auth-endpoints=configs,heartbeat +``` + +{{% /code-tab-content %}} +{{% code-tab-content %}} + + +```bash +export DISABLED_AUTH_ENDPOINTS="configs,heartbeat" + +telegraf_controller --disable-auth-endpoints=configs,heartbeat +``` + +{{% /code-tab-content %}} + {{< /code-tabs-wrapper >}} + +2. [Create an API token](/telegraf/controller/tokens/create/) with read + permissions on the **Configs** API and write permissions on the + **Heartbeat** API. + +3. Use the `INFLUX_TOKEN` environment variable to define the `token` option + in your heartbeat output plugin configuration: + + ```toml { .tc-dynamic-values } + [[outputs.heartbeat]] + # ... + token = "${INFLUX_TOKEN}" + ``` + +4. Define the `INFLUX_TOKEN` environment variable in your Telegraf + environment: + + + ```bash {placeholders="YOUR_TELEGRAF_CONTROLLER_TOKEN"} + export INFLUX_TOKEN=YOUR_TELEGRAF_CONTROLLER_TOKEN + + telegraf --config "https://localhost:8888/api/configs/..." + ``` + + Replace {{% code-placeholder-key %}}`YOUR_TELEGRAF_CONTROLLER_TOKEN`{{% /code-placeholder-key %}} + with your {{% product-name %}} API token. + + > [!Important] + > It's important to use the `INFLUX_TOKEN` environment variable. + > When present, Telegraf uses this specific variable to set the token used + > in the `Authorization` header when requesting the configuration. + +5. Navigate to the **Settings** page in {{% product-name %}} and reenable + authentication on the Configs and Heartbeat APIs. Save your changes. + +### Features + +- Add user authentication and session management with login and setup pages. +- Add user management with invite system, password reset, and password + complexity validation. +- Add token management with create workflow and management pages. +- Add account management page with ownership transfer flow. +- Add settings page. +- Add application version retrieval and display. +- Enhance Heartbeat plugin with logs, status configurations, and agent + status checks. +- Add dynamic parsing component support for Exec and Google Cloud PubSub Push plugins. +- Add plugin support to the Telegraf Builder UI: + - Aerospike (`inputs.aerospike`) + - Alibaba Cloud Monitor Service (Aliyun) (`inputs.aliyuncms`) + - Amazon Elastic Container Service (`inputs.ecs`) + - AMD ROCm System Management Interface (SMI) (`inputs.amd_rocm_smi`) + - AMQP Consumer (`inputs.amqp_consumer`) + - Apache (`inputs.apache`) + - APC UPSD (`inputs.apcupsd`) + - Apache Aurora (`inputs.aurora`) + - Azure Queue Storage (`inputs.azure_storage_queue`) + - Bcache (`inputs.bcache`) + - Beanstalkd (`inputs.beanstalkd`) + - Beat (`inputs.beat`) + - BIND 9 Nameserver (`inputs.bind`) + - Bond (`inputs.bond`) + - Burrow (`inputs.burrow`) + - Ceph Storage (`inputs.ceph`) + - chrony (`inputs.chrony`) + - Cisco Model-Driven Telemetry (MDT) (`inputs.cisco_telemetry_mdt`) + - ClickHouse (`inputs.clickhouse`) + - Google Cloud PubSub Push (`inputs.cloud_pubsub_push`) + - Amazon CloudWatch Metric Streams (`inputs.cloudwatch_metric_streams`) + - Netfilter Conntrack (`inputs.conntrack`) + - Hashicorp Consul (`inputs.consul`) + - Hashicorp Consul Agent (`inputs.consul_agent`) + - Bosch Rexroth ctrlX Data Layer (`inputs.ctrlx_datalayer`) + - Mesosphere Distributed Cloud OS (`inputs.dcos`) + - Device Mapper Cache (`inputs.dmcache`) + - Data Plane Development Kit (DPDK) (`inputs.dpdk`) + - Elasticsearch (`inputs.elasticsearch`) + - Ethtool (`inputs.ethtool`) + - Exec (`inputs.exec`) + - Fibaro (`inputs.fibaro`) + - File (`inputs.file`) + - Filecount (`inputs.filecount`) + - File statistics (`inputs.filestat`) + - Fireboard (`inputs.fireboard`) + - AWS Data Firehose (`inputs.firehose`) + - Fluentd (`inputs.fluentd`) + - Fritzbox (`inputs.fritzbox`) + - GitHub (`inputs.github`) + - gNMI (gRPC Network Management Interface) (`inputs.gnmi`) + - Google Cloud Storage (`inputs.google_cloud_storage`) + - GrayLog (`inputs.graylog`) + - HAProxy (`inputs.haproxy`) + - HDDtemp (`inputs.hddtemp`) + - HTTP (`inputs.http`) + - HTTP Listener v2 (`inputs.http_listener_v2`) + - HueBridge (`inputs.huebridge`) + - Hugepages (`inputs.hugepages`) + - Icinga2 (`inputs.icinga2`) + - InfiniBand (`inputs.infiniband`) + - InfluxDB (`inputs.influxdb`) + - InfluxDB Listener (`inputs.influxdb_listener`) + - InfluxDB V2 Listener (`inputs.influxdb_v2_listener`) + - Intel Baseband Accelerator (`inputs.intel_baseband`) + - Intel® Dynamic Load Balancer (`inputs.intel_dlb`) + - Intel® Platform Monitoring Technology (`inputs.intel_pmt`) + +### Bug fixes + +- Fix default Heartbeat plugin configuration and environment variable exports. + +--- + +## v0.0.4-alpha {date="2026-02-05"} + +### Features + +- Require InfluxData EULA acceptance before starting the server. +- Add plugin support to the Telegraf Builder UI and TOML parser: + - ActiveMQ (`inputs.activemq`) + - Vault (`secretstores.vault`) + - All parsers + - All serializers +- Add support for custom logs directory. +- Reduce binary size. + +### Bug fixes + +- Fix question mark position in deletion popup. + +--- + +## v0.0.3-alpha {date="2026-01-14"} + +### Features + +- Add linux-arm64 binary support. +- Add build validation for missing plugins. +- Add local file handling for configurations. + +--- + +## v0.0.2-alpha {date="2026-01-13"} + +### Features + +- Identify external configurations for Telegraf agents. +- Add SSL support for backend connections. +- Add health check status API endpoint. +- Add `Last-Modified` header to GET TOML API response and remove duplicate + protocol handling. +- Compile native Rust NAPI server for heartbeat service. + +### Bug fixes + +- Fix default parsing unit to use seconds. +- Fix command line string generation. + +--- + +## v0.0.1-alpha {date="2026-01-01"} + +_Initial alpha build of Telegraf Controller._ diff --git a/content/telegraf/controller/settings.md b/content/telegraf/controller/settings.md new file mode 100644 index 000000000..dcbf419da --- /dev/null +++ b/content/telegraf/controller/settings.md @@ -0,0 +1,143 @@ +--- +title: Manage settings +description: > + Configure authentication requirements, login security, and password + policies in Telegraf Controller. +menu: + telegraf_controller: + name: Manage settings +weight: 9 +--- + +Owners and administrators can configure authentication, login security, and +password requirements for {{% product-name %}}. + +Navigate to the **Settings** page from the left navigation menu to view and +modify these settings. + +{{< img-hd src="/img/telegraf/controller-settings.png" alt="Telegraf Controller settings page" />}} + +## Require authentication per endpoint + +{{% product-name %}} organizes API endpoints into groups. +Authentication can be required or disabled for each group independently, giving +you fine-grained control over which resources require credentials. + +| Endpoint group | Covers | +| :---------------- | :------------------------------ | +| `agents` | Agent monitoring and management | +| `configs` | Configuration management | +| `labels` | Label management | +| `reporting-rules` | Reporting rule management | +| `heartbeat` | Agent heartbeat requests | + +When authentication is disabled for a group, anyone with network access can use +those endpoints without an API token. +When enabled, requests require valid authentication. + +> [!Note] +> By default, authentication is required for all endpoints. + +To toggle authentication for endpoint groups: + +1. Navigate to the **Settings** page. +2. Toggle authentication on or off for each endpoint group. +3. Click **Save**. + +> [!Warning] +> Disabling authentication for endpoints means anyone with network access to +> {{% product-name %}} can access those resources without credentials. + +### Environment variable and CLI flag + +You can configure disabled authentication endpoints at startup using the +`DISABLED_AUTH_ENDPOINTS` environment variable or the `--disable-auth-endpoints` +CLI flag. +The value is a comma-separated list of endpoint groups, or `"*"` to disable +authentication for all endpoints. + +```bash +# Disable auth for agents and heartbeat only +export DISABLED_AUTH_ENDPOINTS="agents,heartbeat" + +# Disable auth for all endpoints +export DISABLED_AUTH_ENDPOINTS="*" +``` + +Using the CLI flag: + +```bash +# Disable auth for agents and heartbeat only +./telegraf_controller --disable-auth-endpoints=agents,heartbeat + +# Disable auth for all endpoints +./telegraf_controller --disable-auth-endpoints="*" +``` + +These values are used as initial defaults when {{% product-name %}} creates its settings record for the first time. +After that, changes made through the **Settings** page take precedence. + +## Login security + +### Login attempts + +You can configure the number of failed login attempts allowed before an account is locked out. +The default threshold is 5 attempts, with a minimum of 1. + +To change the login attempt threshold: + +1. Navigate to the **Settings** page. +2. Update the **Login attempts** value. +3. Click **Save**. + +### Login lockout + +When a user exceeds the failed attempt threshold, their account is locked for a configurable duration. +The default lockout duration is 15 minutes, with a minimum of 1 minute. +The lockout clears automatically after the configured duration has elapsed. + +To change the lockout duration: + +1. Navigate to the **Settings** page. +2. Update the **Login lockout duration** value. +3. Click **Save**. + +> [!Tip] +> If a user is locked out, an owner or administrator can [reset their password](/telegraf/controller/users/update/#reset-a-users-password) to unlock the account. + +### Password complexity requirements + +{{% product-name %}} provides three password complexity levels that apply to all +password operations, including initial setup, password changes, password resets, +and invite completion. + +| Level | Min length | Uppercase* | Lowercase* | Digits* | Special characters* | +| :--------- | :--------: | :--------: | :--------: | :-----: | :-----------------: | +| **Low** | 8 | No | No | No | No | +| **Medium** | 10 | Yes | Yes | Yes | No | +| **High** | 12 | Yes | Yes | Yes | Yes | + +{{% caption %}} +\* Passwords require at least one of the defined character types. +{{% /caption %}} + +To change the password complexity level: + +1. Navigate to the **Settings** page. +2. Select the desired **Password complexity** level. +3. Click **Save**. + +> [!Note] +> Changing the password complexity level does not affect existing passwords. The new requirements apply only when users set or change their passwords. + +### Environment variables + +You can set initial defaults for login security settings using environment variables. +These values are applied when {{% product-name %}} initializes its settings for the first time. +Changes made on the **Settings** page override initialized settings. + +| Environment variable | Description | Default | +| :----------------------- | :----------------------------------------- | :-----: | +| `LOGIN_LOCKOUT_ATTEMPTS` | Failed attempts before lockout | `5` | +| `LOGIN_LOCKOUT_MINUTES` | Minutes to lock account | `15` | +| `PASSWORD_COMPLEXITY` | Complexity level (`low`, `medium`, `high`) | `low` | diff --git a/content/telegraf/controller/tokens/_index.md b/content/telegraf/controller/tokens/_index.md new file mode 100644 index 000000000..2a0d01f54 --- /dev/null +++ b/content/telegraf/controller/tokens/_index.md @@ -0,0 +1,69 @@ +--- +title: Manage API tokens +description: > + Create and manage API tokens for authenticating API requests and + Telegraf agent connections to Telegraf Controller. +menu: + telegraf_controller: + name: Manage API tokens +weight: 8 +cascade: + related: + - /telegraf/controller/reference/authorization/ +--- + +API tokens authenticate requests to the {{% product-name %}} API and Telegraf agent connections. +Use tokens to authorize Telegraf agents, heartbeat requests, and external API clients. + +## Token format + +All API tokens use the `tc-apiv1_` prefix, making them easy to identify in +configuration files and scripts. + +The full token value is displayed only once at the time of creation and cannot be retrieved later. +Copy and store the token in a secure location immediately after creating it. + +> [!Important] +> #### Raw token strings are not stored +> +> Tokens are stored as a cryptographic hash. The original value is never saved. +> If you lose a token, you must revoke it and create a new one. + +## Token permissions + +Each token is scoped to a specific user. +Token permissions are restricted to the permissions allowed by the user's role. +A token cannot exceed the permissions of the user it belongs to. + +When you create a token, you can set custom permissions to restrict the token's +access below your full role permissions. +This lets you issue narrowly scoped tokens for specific tasks, such as a token +that can only register agents or a token limited to read-only access. + +## Token states + +Tokens exist in one of two states: + +- **Active** -- The token can be used for authentication. +- **Revoked** -- The token is permanently disabled but the record is retained + for auditing purposes. + +Revoking a token is irreversible. +Any agent or client using a revoked token immediately loses access. + +## Token visibility + +Your role determines which tokens you can view and manage: + +| Role | Token visibility | +|:------------------|:----------------------------------| +| **Owner** | All tokens across all users | +| **Administrator** | All tokens across all users | +| **Manager** | Only their own tokens | +| **Viewer** | Cannot manage tokens | + +> [!Note] +> **Owner** and **Administrator** users can revoke any token in the organization, +> including tokens belonging to other users. + +{{< children hlevel="h2" >}} diff --git a/content/telegraf/controller/tokens/create.md b/content/telegraf/controller/tokens/create.md new file mode 100644 index 000000000..c8b88b661 --- /dev/null +++ b/content/telegraf/controller/tokens/create.md @@ -0,0 +1,63 @@ +--- +title: Create an API token +description: > + Create a new API token for authenticating with the Telegraf Controller API. +menu: + telegraf_controller: + name: Create a token + parent: Manage API tokens +weight: 101 +--- + +Create a new API token to authenticate requests to the {{% product-name %}} API. +Tokens let you grant scoped access to external tools, scripts, and services without sharing your login credentials. + +> [!Important] +> #### Required permissions +> +> You must have an **Owner**, **Administrator**, or **Manager** role assigned to +> your account. + +## Create a token + +1. Navigate to the **API Tokens** page. +2. Click **Create Token**. +3. Enter a **Description** for the token that identifies where or how the token + will be used. +4. _(Optional)_ Set an **Expiration** date. + Tokens without an expiration date remain active indefinitely. +5. _(Optional)_ Set **Custom permissions** to restrict the token's access below + your role's full permissions. + See [Custom permissions](#custom-permissions) for details. +6. Click **Create**. + +{{< img-hd src="/img/telegraf/controller-create-token.png" alt="Telegraf Controller create token form" />}} + +> [!Important] +> #### Copy and store your token +> +> Copy your API token immediately after creation. +> The full token value is only displayed once and cannot be retrieved later. + +## Custom permissions + +When you set custom permissions on a token, {{% product-name %}} intersects +those permissions with your role's existing permissions. +This means you can use custom permissions to narrow a token's access, but you +cannot create a token with more access than your role allows. + +For example, if you have the **Manager** role, you cannot create a token with +user management permissions. +The resulting token will only include the permissions that overlap with what +your role grants. + +Custom permissions are useful when you want to issue a token for a specific task, +such as read-only access to configurations, without exposing the full scope of +your role. + +## If you lose a token + +If you lose or forget a token value, you cannot recover it. +Revoke the lost token and create a new one to restore access. + +For instructions on revoking a token, see [Revoke an API token](/telegraf/controller/tokens/revoke/). diff --git a/content/telegraf/controller/tokens/delete.md b/content/telegraf/controller/tokens/delete.md new file mode 100644 index 000000000..a686707d5 --- /dev/null +++ b/content/telegraf/controller/tokens/delete.md @@ -0,0 +1,60 @@ +--- +title: Delete a token +description: > + Permanently delete an API token from Telegraf Controller. +menu: + telegraf_controller: + name: Delete a token + parent: Manage API tokens +weight: 105 +--- + +Deleting a token immediately removes the token so it cannot be used for authentication. +Unlike revocation, deletion removes all data associated with the token and token +history. + +> [!Warning] +> #### Deleting and API token cannot be undone +> +> Deleting a token is permanent and cannot be undone. Any agents or clients +> using this token will lose access immediately. + +## Delete versus revoke + +{{% product-name %}} supports two ways to remove a token from active use: +**deletion** and **revocation**. + +- **Deleted** tokens are permanently removed from the system. + No record of the token is retained after deletion. +- **Revoked** tokens remain visible in the token list with a **Revoked** status. + This provides an audit trail showing when the token was created and when it + was disabled. Revoked tokens cannot be used for authentication. + +Use revoke when you want to disable a token but maintain an audit trail. +Use delete when you want to completely remove the token and its record from the system. + +For more information about revoking a token, see +[Revoke a token](/telegraf/controller/tokens/revoke/). + +## Delete a token + +1. Navigate to the **API Tokens** page or open the token's detail view. +2. Click **Delete** to initiate the deletion. If on the token detail + page, select the **Manage** tab to reveal the **Delete** action. +3. In the confirmation dialog, confirm that you want to permanently delete the token. + +Once confirmed, the token is immediately deleted. Any agent or integration +that relies on the deleted token will no longer be able to authenticate with +{{% product-name %}}. + +## Bulk delete tokens + +You can delete multiple tokens at once from the **API Tokens** page. + +1. On the **API Tokens** page, select the checkboxes next to each token you want to delete. +2. Click the **Delete** option in the bulk actions bar. +3. In the confirmation dialog, review the number of tokens to be deleted and confirm. + +All selected tokens are permanently removed and immediately invalidated. +Verify that no active agents depend on the selected tokens before confirming the +bulk deletion. diff --git a/content/telegraf/controller/tokens/reassign.md b/content/telegraf/controller/tokens/reassign.md new file mode 100644 index 000000000..0ed6a9137 --- /dev/null +++ b/content/telegraf/controller/tokens/reassign.md @@ -0,0 +1,64 @@ +--- +title: Reassign a token +description: > + Reassign an API token from one user to another in Telegraf Controller. +menu: + telegraf_controller: + name: Reassign a token + parent: Manage API tokens +weight: 103 +--- + +Reassigning an API token from one user to another in Telegraf Controller lets +you transfer ownership of that token to another user without disrupting any +external clients using the token. + +> [!Important] +> #### Required permissions +> +> To reassign an API token, you must have the **Owner** or **Administrator** +> role in {{% product-name %}}. + +## Reassign a token + +You can reassign an individual token from one user to another directly from the +token's detail view or the tokens list. + +1. In {{% product-name %}}, navigate to the **API Tokens** page or open the + detail page for the token you want to reassign. +2. Click **Reassign** on the token you want to transfer. If on the token detail + page, select the **Manage** tab to reveal the **Reassign** action. +3. In the dialog that appears, select the target user you want to assign the + token to. +4. Click **Confirm** to complete the reassignment. + +> [!Important] +> When you reassign a token, its permissions are automatically restricted to +> match the target user's role. For example, a token with full access reassigned +> to a Viewer becomes a read-only token. + +## Bulk reassign + +If you need to reassign multiple tokens at once, use the bulk reassign option. + +1. On the **API Tokens** page, select the checkboxes next to the tokens you want + to reassign. +2. Click the **Reassign** option in the bulk actions bar. +3. Select the target user you want to assign the selected tokens to. +4. Click **Confirm** to reassign all selected tokens. + +The same permission restriction applies during bulk reassignment. Each token's +permissions are adjusted to align with the target user's role. + +## When to reassign + +Reassigning tokens lets you transfer ownership without revoking and recreating +tokens. This is useful in several common scenarios: + +- **Offboarding a user**: A user is leaving the organization and their tokens + should continue working under another account. + Reassigning ensures active integrations are not disrupted. +- **Reorganizing responsibilities**: Team members are shifting roles or + responsibilities and token ownership should reflect the new structure. +- **Consolidating ownership after role changes**: After updating user roles, you + may want to consolidate tokens under a single account to simplify token management. diff --git a/content/telegraf/controller/tokens/revoke.md b/content/telegraf/controller/tokens/revoke.md new file mode 100644 index 000000000..c82556a74 --- /dev/null +++ b/content/telegraf/controller/tokens/revoke.md @@ -0,0 +1,61 @@ +--- +title: Revoke a token +description: > + Revoke an API token to immediately prevent its use while keeping + the token record for auditing. +menu: + telegraf_controller: + name: Revoke a token + parent: Manage API tokens +weight: 104 +--- + +Revoking a token immediately prevents it from being used for authentication +while keeping the token record in the system for auditing purposes. +Unlike deletion, revocation preserves a full history of the token, including +when it was created and when it was disabled. + +## Revoke versus delete + +{{% product-name %}} supports two ways to remove a token from active use: +**revocation** and **deletion**. + +- **Revoked** tokens remain visible in the token list with a **Revoked** status. + This provides an audit trail showing when the token was created and when it + was disabled. Revoked tokens cannot be used for authentication. +- **Deleted** tokens are permanently removed from the system. + No record of the token is retained after deletion. + +Use revoke when you want to disable a token but maintain an audit trail. +Use delete when you want to completely remove the token and its record from the system. + +For more information about deleting a token, see +[Delete a token](/telegraf/controller/tokens/delete/). + +## Revoke a token + +1. Navigate to the **API Tokens** page, or open the token's detail view. +2. Click **Revoke**. If on the token detail page, select the **Manage** tab to + reveal the **Revoke** action. +3. Confirm the revocation in the dialog. + +The token status changes to **Revoked** and any requests that use the token are +immediately rejected. + +> [!Note] +> #### You cannot reactivate a revoked token +> +> Revocation is permanent. You cannot re-activate a revoked token. +> If you need to restore access, create a new token. +> See [Create a token](/telegraf/controller/tokens/create/). + +## Bulk revoke + +To revoke multiple tokens at once: + +1. On the **API Tokens** page, select the tokens you want to revoke. +2. Click **Revoke** in the bulk actions bar. +3. Confirm the revocation in the dialog. + +All selected tokens are immediately revoked and can no longer be used for +authentication. diff --git a/content/telegraf/controller/tokens/use.md b/content/telegraf/controller/tokens/use.md new file mode 100644 index 000000000..735935838 --- /dev/null +++ b/content/telegraf/controller/tokens/use.md @@ -0,0 +1,81 @@ +--- +title: Use API tokens +description: > + Use API tokens to authenticate Telegraf agents, heartbeat requests, + and external API clients with Telegraf Controller. +menu: + telegraf_controller: + name: Use tokens + parent: Manage API tokens +weight: 102 +--- + +API tokens authenticate requests to {{% product-name %}}. +Use tokens to connect Telegraf agents, authorize heartbeat reporting, and +integrate external API clients. + +## With Telegraf agents + +Configure your Telegraf agent to include an API token when retrieving +configurations and reporting heartbeats to {{% product-name %}}. + +Telegraf agents require API tokens with the following permissions: + +- **Configs**: Read +- **Heartbeat**: Write + +### Use the INFLUX_TOKEN environment variable + +When retrieving a configuration from a URL, Telegraf only sends an `Authorization` +when it detects the `INFLUX_TOKEN` environment variable. To authorize Telegraf +to retrieve a configuration from {{% product-name %}}, define the `INFLUX_TOKEN` +environment variable: + + +```bash { placeholders="YOUR_TC_API_TOKEN" } +export INFLUX_TOKEN=YOUR_TC_API_TOKEN + +telegraf \ + --config "http://telegraf_controller.example.com/api/configs/xxxxxx/toml +``` + +Replace {{% code-placeholder-key %}}`YOUR_TC_API_TOKEN`{{% /code-placeholder-key %}} +with your {{% product-name %}} API token. + +### For heartbeat requests + +Telegraf uses the [Heartbeat output plugin](/telegraf/v1/output-plugins/heartbeat/) +to send heartbeats to {{% product-name %}}. +Use the `INFLUX_TOKEN` environment variable to define the `token` option in your +heartbeat plugin configuration. +Telegraf uses the environment variable value defined when starting Telegraf. + +```toml { .tc-dynamic-values } +[[outputs.heartbeat]] + url = "http://telegraf_controller.example.com/agents/heartbeat" + instance_id = "&{agent_id}" + interval = "1m" + include = ["hostname", "statistics", "configs"] + token = "${INFLUX_TOKEN}" +``` + +When authentication is required for the heartbeat endpoint, agents must include +a valid token with each heartbeat request. +If a heartbeat request is missing a token or includes an invalid token, +{{% product-name %}} rejects the request and the agent's status is not updated. + +## With external API clients + +Include the token in the `Authorization` header when making API requests to +{{% product-name %}}: + +``` +Authorization: Bearer tc-apiv1_ +``` + +The token's permissions determine which API endpoints and operations are accessible. +Requests made with a token that lacks the required permissions are rejected with an authorization error. + +> [!Note] +> If authentication is disabled for an endpoint group in **Settings**, requests to those endpoints do not require a token. +> See [Settings](/telegraf/controller/settings/#require-authentication-per-endpoint) for details on configuring authentication requirements per endpoint. diff --git a/content/telegraf/controller/users/_index.md b/content/telegraf/controller/users/_index.md new file mode 100644 index 000000000..5e67959dd --- /dev/null +++ b/content/telegraf/controller/users/_index.md @@ -0,0 +1,46 @@ +--- +title: Manage users +description: > + Manage user accounts in Telegraf Controller, including creating, updating, + disabling, and deleting users. +menu: + telegraf_controller: + name: Manage users +weight: 7 +cascade: + related: + - /telegraf/controller/reference/authorization/ +--- + +Users are accounts that can log into the {{% product-name %}} web interface and +interact with the system based on their assigned role. +You can create, update, disable, and delete users to control who has access to +your {{% product-name %}} instance. + +## User states + +Each user account is in one of the following states: + +- **Active** --- The user can log in and perform actions based on their assigned + role. +- **Disabled** --- The user cannot log in. Existing API tokens remain associated + with the account but are unusable while the user is disabled. +- **Locked** --- A temporary state triggered by too many failed login attempts. + The lock clears automatically after the configured lockout period. See the + [Settings](/telegraf/controller/settings/) page for configuration options. + +## User roles + +{{% product-name %}} supports four roles with different levels of access: + +| Role | Access level | +|:------------------|:--------------------------------------------------------------------| +| **Owner** | Full access. Manages users, tokens, and settings. | +| **Administrator** | Full access except ownership transfer. | +| **Manager** | Manages configs, agents, labels, reporting rules, and own tokens. | +| **Viewer** | Read-only access. | + +For more details about roles and permissions, see +[Authorization](/telegraf/controller/reference/authorization/). + +{{< children hlevel="h2" >}} diff --git a/content/telegraf/controller/users/account.md b/content/telegraf/controller/users/account.md new file mode 100644 index 000000000..cbb9d9fe5 --- /dev/null +++ b/content/telegraf/controller/users/account.md @@ -0,0 +1,54 @@ +--- +title: Manage your account +description: > + Update your username, email address, and password in Telegraf Controller. +menu: + telegraf_controller: + name: Manage your account + parent: Manage users +weight: 101 +--- + +Any authenticated user can update their own account details from the account page. +Use the account page to change your username, email address, or password at any time. + +{{< img-hd src="/img/telegraf/controller-account-page.png" alt="Telegraf Controller account page" />}} + +## Update your username + +Your username is your display name throughout {{% product-name %}}. +Each username must be unique across the system. + +1. Click your profile icon in the top-right corner and select **Account**. +2. In the **Username** field, enter your new username. +3. Click **Save**. + +If the username you entered is already taken, {{% product-name %}} displays an +error. Choose a different username and try again. + +## Update your email address + +Each email address must be unique and in a valid format. + +1. Click your profile icon in the top-right corner and select **Account**. +2. In the **Email** field, enter your new email address. +3. Click **Save**. + +If the email address is already associated with another account or is not in a +valid format, {{% product-name %}} displays an error. +Correct the email address and try again. + +## Update your password + +To change your password, you must provide your current password along with the +new one. + +1. Click your profile icon in the top-right corner and select **Account**. +2. In the **Current Password** field, enter your existing password. +3. In the **New Password** field, enter your new password. +4. In the **Confirm Password** field, re-enter the new password. +5. Click **Save**. + +> [!Note] +> Your new password must meet the password complexity requirements configured by your administrator. +> For more information, see [Password requirements](/telegraf/controller/settings/#password-requirements). diff --git a/content/telegraf/controller/users/delete.md b/content/telegraf/controller/users/delete.md new file mode 100644 index 000000000..3380df838 --- /dev/null +++ b/content/telegraf/controller/users/delete.md @@ -0,0 +1,48 @@ +--- +title: Delete a user +description: > + Permanently delete a user account and all associated API tokens from + Telegraf Controller. +menu: + telegraf_controller: + name: Delete a user + parent: Manage users +weight: 106 +--- + +> [!Warning] +> #### Deleting a user cannot be undone +> +> Deleting a user is permanent and cannot be undone. +> All of the user's API tokens are also deleted. + +## What deletion removes + +When you delete a user from {{% product-name %}}, the following are permanently +removed: + +- User account and credentials +- All API tokens owned by the user +- All active sessions + +## Delete a user + +1. In the {{% product-name %}} UI, navigate to **Users** and click the user you + want to delete to open their detail page. +2. Click **Delete User**. +3. In the confirmation dialog, confirm the deletion. + +The user is immediately removed and can no longer authenticate with +{{% product-name %}}. + +## Restrictions + +- You cannot delete your own account. +- You cannot delete the owner — you must + [transfer ownership](/telegraf/controller/users/transfer-ownership/) first. +- Only the owner can delete administrator accounts. + +> [!Tip] +> If you're unsure whether to delete a user, consider +> [disabling them](/telegraf/controller/users/disable/) first. +> Disabled accounts can be re-enabled later. diff --git a/content/telegraf/controller/users/disable.md b/content/telegraf/controller/users/disable.md new file mode 100644 index 000000000..6f047f9db --- /dev/null +++ b/content/telegraf/controller/users/disable.md @@ -0,0 +1,41 @@ +--- +title: Disable a user +description: > + Disable a user account to prevent login without deleting the account + or its associated tokens. +menu: + telegraf_controller: + name: Disable a user + parent: Manage users +weight: 105 +--- + +Disabling a user prevents them from logging in without permanently deleting their account or tokens. +This is useful when you want to temporarily revoke access or are unsure whether to delete the account. + +## What disabling does + +When you disable a user account in {{% product-name %}}: + +- The user cannot log in to the web interface. +- All active sessions are destroyed immediately. +- Existing API tokens remain in the system but cannot be used for authentication + while the user is disabled. +- The user's data (account details, token records) is preserved. + +## Disable a user + +1. Navigate to the user's detail page. +2. Toggle the user's status to **Disabled** (or click the **Disable** option). +3. Confirm the action. + +> [!Note] +> You cannot disable your own account or the **Owner** account. + +## Re-enable a user + +1. Navigate to the disabled user's detail page. +2. Toggle the user's status to **Active** (or click the **Enable** option). + +Once re-enabled, the user can log in immediately with their existing credentials. +Their API tokens also become usable again. diff --git a/content/telegraf/controller/users/invite.md b/content/telegraf/controller/users/invite.md new file mode 100644 index 000000000..5fd5ded2e --- /dev/null +++ b/content/telegraf/controller/users/invite.md @@ -0,0 +1,76 @@ +--- +title: Invite a new user +description: > + Invite new users to Telegraf Controller by generating an invite link with + a pre-assigned role. +menu: + telegraf_controller: + name: Invite a new user + parent: Manage users +weight: 102 +--- + +Owners and administrators can invite new users to {{% product-name %}} by +generating an invite link with a pre-assigned role and expiration. +The invited user opens the link, sets a password, and their account is +immediately active. + +> [!Note] +> You must have the **Owner** or **Administrator** role to create invites. + +## Create an invite + +1. Navigate to the **Users** page. +2. Click the {{% icon "plus" %}} **Invite User** button. +3. Enter a **Username** for the new user (3--50 characters). +4. Enter the user's **Email** address. +5. Select a **Role** for the new user: + - **Administrator** -- full access to all resources and user management. + - **Manager** -- can manage configurations, agents, and labels but cannot + manage users. + - **Viewer** -- read-only access to all resources. +6. Set the invite **Expiration** in hours. The default is 72 hours. Valid + values range from 1 to 720 hours (30 days). +7. Click **Create Invite**. + +{{< img-hd src="/img/telegraf/controller-invite-user.png" alt="Telegraf Controller invite user form" />}} + +> [!Note] +> You cannot invite a user with the **Owner** role. To make someone the owner, +> first invite them as an **Administrator**, then +> [transfer ownership](/telegraf/controller/users/transfer-ownership/). + +## Share the invite link + +After creating the invite, {{% product-name %}} displays a unique invite link. +Copy the link and share it with the user through your preferred communication +channel (email, chat, etc.). + +The link expires after the duration you configured. Once expired, the link can +no longer be used and you must create a new invite. + +## Accept an invite + +The invited user completes the following steps to activate their account: + +1. Open the invite link in a browser. +2. Set a password that meets the configured complexity requirements. +3. Click **Create Account**. + +The account activates immediately and the user is automatically logged in with +the role assigned during the invite. + +## Manage pending invites + +You can view and manage all pending invites from the **Users** page. +Pending invites appear in a separate list above active users. + +To revoke a pending invite before it is used: + +1. Navigate to the **Users** page. +2. Locate the pending invite you want to remove. +3. Click the **Delete** button next to the invite. +4. Confirm the deletion when prompted. + +Deleting a pending invite invalidates the invite link. The invited user can no +longer use it to create an account. diff --git a/content/telegraf/controller/users/transfer-ownership.md b/content/telegraf/controller/users/transfer-ownership.md new file mode 100644 index 000000000..99e5d9432 --- /dev/null +++ b/content/telegraf/controller/users/transfer-ownership.md @@ -0,0 +1,57 @@ +--- +title: Transfer ownership +description: > + Transfer the Telegraf Controller owner role to another administrator. +menu: + telegraf_controller: + name: Transfer ownership + parent: Manage users +weight: 104 +--- + +The **Owner** role grants full administrative access to {{% product-name %}}, +including the ability to manage all users, tokens, and settings. Only one owner +can exist at a time. The current owner can transfer ownership to any active +administrator. + +## Prerequisites and restrictions + +- Only the current **Owner** can transfer ownership. +- The target user must have the **Administrator** role and be in an active state. +- If the target user is a **Manager** or **Viewer**, you must first promote them + to **Administrator**. See + [Change a user's role](/telegraf/controller/users/update/#change-a-users-role). +- You cannot transfer ownership to yourself. + +## Transfer the owner role + +1. Navigate to the **Users** page or the target user's detail page. +2. Choose the target **Administrator** from the list (if not already selected). +3. Select the **Make Owner** option. If on the user detail page, select the + **Manage** tab to reveal the **Make Owner** option. +4. Confirm the username of the user you want to transfer ownership to and click + **Transfer Ownership**. + +{{< img-hd src="/img/telegraf/controller-transfer-ownership.png" alt="Telegraf Controller transfer ownership confirmation" />}} + +## What happens during transfer + +When you confirm the transfer, {{% product-name %}} performs an atomic operation +that updates both accounts simultaneously: + +- The current owner is demoted to **Administrator**. +- The target user is promoted to **Owner**. +- Both users' sessions are destroyed -- both must log in again. +- The operation is atomic: both changes succeed together or neither takes effect. + +> [!Tip] +> #### Coordinate ownership transfers +> +> Coordinate with the target user before transferring ownership. Both accounts +> are logged out immediately after the transfer completes. + +> [!Warning] +> #### You cannot reclaim the Owner role yourself +> +> Once transferred, you cannot reclaim the **Owner** role yourself. The new +> owner must transfer it back to you. diff --git a/content/telegraf/controller/users/update.md b/content/telegraf/controller/users/update.md new file mode 100644 index 000000000..846b2734c --- /dev/null +++ b/content/telegraf/controller/users/update.md @@ -0,0 +1,84 @@ +--- +title: Update users +description: > + Reset user passwords, change user roles, and manage user accounts in + Telegraf Controller. +menu: + telegraf_controller: + name: Update users + parent: Manage users +weight: 103 +--- + +Owners and administrators can reset passwords and change roles for other users in {{% product-name %}}. +These actions help maintain account security and ensure users have the appropriate level of access. + +## Reset a user's password + +When a user forgets their password or needs a credential refresh, you can +generate a time-limited reset link for them. + +> [!Note] +> You must have the **Owner** or **Administrator** role to reset passwords. +> Only the **Owner** can reset **Administrator** passwords. + +### Generate a password reset link + +1. Navigate to the user's detail page. +2. Click **Reset Password**. +3. Set the link expiration. The default is 24 hours, but you can configure it from 1 to 720 hours. +4. Click **Generate Link** to create the reset link. +5. Copy the generated reset link and share it with the user through a secure channel. + +### Complete a password reset + +After receiving a reset link, the user completes the following steps: + +1. Open the reset link in a browser. +2. Enter a new password that meets the complexity requirements. +3. Click **Submit** to save the new password. + +> [!Note] +> The user is not automatically logged in after resetting their password. +> They must log in with their new credentials. + +### Emergency owner password reset + +If the owner account is locked out or the owner has forgotten their password, +you can reset it using environment variables. + +1. Set the following environment variables: + - `RESET_OWNER_PASSWORD=true` + - `OWNER_PASSWORD` to the desired new password +2. Restart the {{% product-name %}} application. +3. Log in with the new password. +4. Remove the `RESET_OWNER_PASSWORD` and `OWNER_PASSWORD` environment variables. + +> [!Warning] +> Remove `RESET_OWNER_PASSWORD` and `OWNER_PASSWORD` environment variables after successfully logging in. Leaving them set causes the password to reset on every application restart. + +## Change a user's role + +You can promote or demote users by changing their assigned role. + +> [!Note] +> You must have the **Owner** or **Administrator** role to change a user's role. +> Only the **Owner** can change a user's role to **Administrator**. + +1. Navigate to the user's detail page. +2. Select the user's new role. +3. Confirm the change when prompted. + +The following restrictions apply to role changes: + +- You cannot assign the **Owner** role directly. To make a user the owner, + the current owner must [transfer ownership](/telegraf/controller/users/transfer-ownership/). + +> [!Important] +> #### Side effects of changing a user's role +> +> - The user's API tokens are reclamped to match the new role's permissions. +> If the new role cannot manage tokens (such as **Viewer**), all active tokens +> are revoked. +> - The user's active sessions are destroyed. They must log in again to continue +> using {{% product-name %}}. diff --git a/cypress/e2e/content/tc-downloads.cy.js b/cypress/e2e/content/tc-downloads.cy.js new file mode 100644 index 000000000..c7d8045c1 --- /dev/null +++ b/cypress/e2e/content/tc-downloads.cy.js @@ -0,0 +1,103 @@ +/// + +/** + * E2E tests for the Telegraf Controller gated downloads module (tc-downloads.js). + * + * Tests the four key user-facing behaviors: + * 1. Gated state — no localStorage key → button visible, links hidden + * 2. Ungated state — localStorage key present → links rendered, button hidden + * 3. Query param — ?ref=tc visit → key set, downloads shown + * 4. SHA copy button — present when downloads are rendered + * + * Marketo form submission is NOT tested (external dependency). + */ + +const PAGE_URL = '/telegraf/controller/install/'; +const STORAGE_KEY = 'influxdata_docs_tc_dl'; + +describe('Telegraf Controller gated downloads', () => { + describe('Gated state (no localStorage key)', () => { + beforeEach(() => { + // Clear any existing key so the page starts in the gated state. + cy.clearLocalStorage(); + cy.visit(PAGE_URL); + }); + + it('shows the download button', () => { + cy.get('#tc-download-btn').should('be.visible'); + }); + + it('keeps the download links container hidden', () => { + cy.get('#tc-downloads-links').should('not.be.visible'); + }); + + it('does not render download link anchors', () => { + cy.get('.tc-download-link').should('not.exist'); + }); + }); + + describe('Ungated state (localStorage key present)', () => { + beforeEach(() => { + cy.clearLocalStorage(); + cy.visit(PAGE_URL, { + onBeforeLoad(win) { + win.localStorage.setItem(STORAGE_KEY, 'true'); + }, + }); + }); + + it('hides the download button', () => { + cy.get('#tc-download-btn').should('not.be.visible'); + }); + + it('shows the downloads container', () => { + cy.get('#tc-downloads-links').should('be.visible'); + }); + + it('renders at least one download link', () => { + cy.get('.tc-download-link').should('have.length.at.least', 1); + }); + + it('renders SHA copy buttons for each build', () => { + cy.get('.tc-copy-sha').should('have.length.at.least', 1); + }); + }); + + describe('Query param flow (?ref=tc)', () => { + beforeEach(() => { + cy.clearLocalStorage(); + cy.visit(`${PAGE_URL}?ref=tc`); + }); + + it('sets the localStorage key', () => { + cy.window().then((win) => { + expect(win.localStorage.getItem(STORAGE_KEY)).to.equal('true'); + }); + }); + + it('shows download links after the param is processed', () => { + cy.get('.tc-download-link').should('have.length.at.least', 1); + }); + + it('strips the ?ref=tc param from the URL', () => { + cy.url().should('not.include', 'ref=tc'); + }); + }); + + describe('SHA copy button', () => { + beforeEach(() => { + cy.clearLocalStorage(); + cy.visit(PAGE_URL, { + onBeforeLoad(win) { + win.localStorage.setItem(STORAGE_KEY, 'true'); + }, + }); + }); + + it('each copy button carries a data-sha attribute', () => { + cy.get('.tc-copy-sha').each(($btn) => { + expect($btn.attr('data-sha')).to.be.a('string').and.not.be.empty; + }); + }); + }); +}); diff --git a/data/notifications.yaml b/data/notifications.yaml index e0fde317a..abd090073 100644 --- a/data/notifications.yaml +++ b/data/notifications.yaml @@ -40,6 +40,42 @@ # - [The plan for InfluxDB 3.0 Open Source](https://influxdata.com/blog/the-plan-for-influxdb-3-0-open-source) # - [InfluxDB 3.0 benchmarks](https://influxdata.com/blog/influxdb-3-0-is-2.5x-45x-faster-compared-to-influxdb-open-source/) +- id: telegraf-enterprise-beta + level: note + scope: + - / + exclude: + - /platform/ + - /resources/ + - /kapacitor/ + - /chronograf/ + - /enterprise_influxdb/ + - /influxdb3/ + - /influxdb/ + - /flux/ + title: Telegraf Enterprise now in public beta + slug: | + Get early access to the **Telegraf Controller** and provide feedback to help + shape the future of **Telegraf Enterprise**. + + See the Blog Post + message: | + The upcoming Telegraf Enterprise offering is for organizations running + Telegraf at scale and is comprised of two key components: + + - **Telegraf Controller**: A control plane (UI + API) that centralizes Telegraf configuration management and agent health visibility. + - **Telegraf Enterprise Support**: Official support for Telegraf Controller and Telegraf plugins. + + Join the Telegraf Enterprise beta + to get early access to the Telegraf Controller and provide feedback to help + shape the future of Telegraf Enterprise. + + For more information: + + - [See the announcement blog post](https://www.influxdata.com/blog/telegraf-enterprise-beta) + - [Telegraf Controller Documentation](/telegraf/controller/) + - [Download and install Telegraf Controller](/telegraf/controller/install/) + - id: influxdb3.8-explorer-1.6 level: note scope: diff --git a/data/tc_downloads.yml b/data/tc_downloads.yml new file mode 100644 index 000000000..5db624111 --- /dev/null +++ b/data/tc_downloads.yml @@ -0,0 +1,24 @@ +version: "0.0.5-beta" +platforms: + - name: Linux + builds: + - arch: x64 + os: linux + sha256: "854592b5e1f1922774074036650ed94fc278d9a666b20d35c98e75defb56d2cf" + - arch: arm64 + os: linux + sha256: "15ea90cc93bc345ce77e4b7eb15efa36522efb7026433f25098280fb6577ca91" + - name: macOS + builds: + - arch: x64 + os: macos + sha256: "3ac978da3619f396b78fe51db32cbcc6365af41b6e53ad28eec393eccf3a53a2" + - arch: arm64 + os: macos + sha256: "5c64a3dd3b211cbb0fa3b1e833ca0cb88bbf32209802533b138018a939892562" + - name: Windows + builds: + - arch: x64 + os: win + ext: .exe + sha256: "b98d5034d8cbeb84efeed754688906500c528a54b70fdb33a338a60f13316f94" diff --git a/layouts/_default/_markup/render-codeblock.html b/layouts/_default/_markup/render-codeblock.html index 1e62f2035..a46f2e0f7 100644 --- a/layouts/_default/_markup/render-codeblock.html +++ b/layouts/_default/_markup/render-codeblock.html @@ -5,5 +5,9 @@ {{ $withPlaceholders := replaceRE .Attributes.placeholders $elReplace $highlightedCode }} {{ $withPlaceholders | safeHTML }} {{ else }} -{{ $result.Wrapped }} -{{ end }} \ No newline at end of file + {{- $wrapped := string $result.Wrapped -}} + {{- if in $wrapped "tc-dynamic-values" -}} + {{- $wrapped = replace $wrapped "tc-dynamic-values" "tc-dynamic-values\" data-component=\"tc-dynamic-values" -}} + {{- end -}} + {{ $wrapped | safeHTML }} +{{ end }} diff --git a/layouts/index.html b/layouts/index.html index 81859367a..f26f132ab 100644 --- a/layouts/index.html +++ b/layouts/index.html @@ -128,12 +128,29 @@

Collect data with Telegraf

-

The data collection agent that supports a large catalog of data sources and targets.

- +
+
+
+

Telegraf {{ $telegrafVersion }}

+

The open source data collection agent with support for a large catalog of data sources and targets.

+
+ +
+
+
+

Telegraf Controller

+

Centralized Telegraf configuration management and agent observability with an intuitive UI.

+
+ +
+
@@ -201,16 +218,6 @@

Other Products

-
-
-

Telegraf {{ $telegrafVersion }}

-

The collection agent that gathers time series data from many different sources.

-
- -

Chronograf {{ $chronografVersion }}

diff --git a/layouts/partials/article/special-state.html b/layouts/partials/article/special-state.html index fea71cd19..98cbe6b21 100644 --- a/layouts/partials/article/special-state.html +++ b/layouts/partials/article/special-state.html @@ -18,21 +18,63 @@ {{ if in $productPathWhitelist (print $product "/" $version )}}
-

{{ $displayName }} is in Private Alpha

+

{{ $displayName }} is in Public Beta

- {{ $displayName }} is in private alpha. If you are interested in being a - part of the private alpha program, please sign up: -

-

Sign Up for the Alpha

-

- While in alpha, {{ $displayName }} is not meant for production use. + {{ $displayName }} is in public beta and will be part of the future Telegraf Enterprise offering. + While in beta, {{ $displayName }} is not meant for production use. The {{ $displayName}} documentation is a work in progress, and we are actively working to improve it. If you have any questions or suggestions, please submit an issue. We welcome any and all contributions.

-
+
+

+ Beta expectations +

+ +
+
+

+ Provide beta feedback +

+ +
+

Join our public channels

diff --git a/layouts/partials/footer/modals.html b/layouts/partials/footer/modals.html index 9830135dd..56f27291f 100644 --- a/layouts/partials/footer/modals.html +++ b/layouts/partials/footer/modals.html @@ -14,6 +14,9 @@ {{ if $inStdlib }} {{ partial "footer/modals/flux-influxdb-versions.html" . }} {{ end }} + {{ if .Page.HasShortcode "telegraf/tc-downloads" }} + {{ partial "footer/modals/tc-downloads.html" . }} + {{ end }}
\ No newline at end of file diff --git a/layouts/partials/footer/modals/tc-downloads.html b/layouts/partials/footer/modals/tc-downloads.html new file mode 100644 index 000000000..882c25545 --- /dev/null +++ b/layouts/partials/footer/modals/tc-downloads.html @@ -0,0 +1,11 @@ + diff --git a/layouts/partials/sidebar.html b/layouts/partials/sidebar.html index 494bc0183..359d50781 100644 --- a/layouts/partials/sidebar.html +++ b/layouts/partials/sidebar.html @@ -35,6 +35,8 @@ {{ .Scratch.Set "searchPlaceholder" "Search the docs" }} {{ else if (eq $currentVersion nil) }} {{ .Scratch.Set "searchPlaceholder" (print "Search " (index .Site.Data.products $product).name) }} +{{ else if (eq $product "telegraf") }} + {{ .Scratch.Set "searchPlaceholder" (print "Search " (cond (eq $currentVersion "v1") "Telegraf" "Telegraf Controller")) }} {{ else if eq $product "influxdb" }} {{ if eq $currentVersion "v3" }} {{ .Scratch.Set "searchPlaceholder" "Search InfluxDB OSS v3" }} diff --git a/layouts/partials/topnav/product-selector.html b/layouts/partials/topnav/product-selector.html index 7f2271c20..25089d004 100644 --- a/layouts/partials/topnav/product-selector.html +++ b/layouts/partials/topnav/product-selector.html @@ -90,7 +90,7 @@ Identify products by their product path. Dictionary schema:

Telegraf

  • {{ template "productLink" (merge (dict "productPath" "telegraf/v1") $templateDefaults) }}
  • -
  • {{ template "productLink" (merge (dict "productPath" "telegraf/controller" "state" "alpha") $templateDefaults) }}
  • +
  • {{ template "productLink" (merge (dict "productPath" "telegraf/controller" "state" "beta") $templateDefaults) }}
diff --git a/layouts/shortcodes/telegraf/dynamic-values.html b/layouts/shortcodes/telegraf/dynamic-values.html deleted file mode 100644 index ec7d76bb9..000000000 --- a/layouts/shortcodes/telegraf/dynamic-values.html +++ /dev/null @@ -1,21 +0,0 @@ -{{- /* Define more precise regex patterns for each dynamic value type */ -}} -{{- /* Note: markdownify converts & to & so we need to match that */ -}} -{{- $paramsRegex := `&\{[^}]+\}` -}} -{{- $envsRegex := `\$\{[^}]+\}` -}} -{{- $secretsRegex := `@\{[^:]+:[^}]+\}` -}} - -{{- /* Get the inner content and markdownify it */ -}} -{{- $code := .Inner | markdownify -}} - -{{- /* Apply replacements for each type of dynamic value */ -}} -{{- /* Replace parameters with span class="param" */ -}} -{{- $code = replaceRE $paramsRegex `$0` $code -}} - -{{- /* Replace environment variables with span class="env" */ -}} -{{- $code = replaceRE $envsRegex `$0` $code -}} - -{{- /* Replace secrets with span class="secret" */ -}} -{{- $code = replaceRE $secretsRegex `$0` $code -}} - -{{- /* Output the processed code */ -}} -{{ $code | safeHTML }} \ No newline at end of file diff --git a/layouts/shortcodes/telegraf/tc-downloads.html b/layouts/shortcodes/telegraf/tc-downloads.html new file mode 100644 index 000000000..a97f4ffcb --- /dev/null +++ b/layouts/shortcodes/telegraf/tc-downloads.html @@ -0,0 +1,37 @@ +{{/* + tc-downloads shortcode + Renders a gated download experience for Telegraf Controller. + - Shows a "Download" button that opens a contact form modal. + - After form submission (or email link with ?ref=tc), JS renders + download links from the JSON data attribute. + - Data sourced from data/tc_downloads.yml (metadata only — URLs are + constructed here at build time). +*/}} +{{- $data := .Site.Data.tc_downloads -}} +{{- $baseURL := "https://telegraf-controller-artifacts.s3.us-east-1.amazonaws.com" -}} +{{- $version := $data.version -}} + +{{/* Build enriched platform data with constructed URLs */}} +{{- $platforms := slice -}} +{{- range $data.platforms -}} + {{- $builds := slice -}} + {{- range .builds -}} + {{- $ext := .ext | default "" -}} + {{- $filename := printf "telegraf_controller-%s-%s%s" .os .arch $ext -}} + {{- $url := printf "%s/v%s/%s" $baseURL $version $filename -}} + {{- $build := dict "arch" .arch "os" .os "sha256" .sha256 "filename" $filename "url" $url -}} + {{- $builds = $builds | append $build -}} + {{- end -}} + {{- $platforms = $platforms | append (dict "name" .name "builds" $builds) -}} +{{- end -}} + +{{- $enriched := dict "version" $version "platforms" $platforms -}} + diff --git a/static/img/telegraf/controller-account-page.png b/static/img/telegraf/controller-account-page.png new file mode 100644 index 000000000..c21f59a7c Binary files /dev/null and b/static/img/telegraf/controller-account-page.png differ diff --git a/static/img/telegraf/controller-agents-list.png b/static/img/telegraf/controller-agents-list.png index b46ab5bfa..4dfca4c97 100644 Binary files a/static/img/telegraf/controller-agents-list.png and b/static/img/telegraf/controller-agents-list.png differ diff --git a/static/img/telegraf/controller-command-builder-dl.png b/static/img/telegraf/controller-command-builder-dl.png new file mode 100644 index 000000000..2e3e3eeba Binary files /dev/null and b/static/img/telegraf/controller-command-builder-dl.png differ diff --git a/static/img/telegraf/controller-create-token.png b/static/img/telegraf/controller-create-token.png new file mode 100644 index 000000000..617f12794 Binary files /dev/null and b/static/img/telegraf/controller-create-token.png differ diff --git a/static/img/telegraf/controller-invite-user.png b/static/img/telegraf/controller-invite-user.png new file mode 100644 index 000000000..f059cc89e Binary files /dev/null and b/static/img/telegraf/controller-invite-user.png differ diff --git a/static/img/telegraf/controller-settings.png b/static/img/telegraf/controller-settings.png new file mode 100644 index 000000000..7cd013e97 Binary files /dev/null and b/static/img/telegraf/controller-settings.png differ diff --git a/static/img/telegraf/controller-setup-owner-account.png b/static/img/telegraf/controller-setup-owner-account.png new file mode 100644 index 000000000..9df863661 Binary files /dev/null and b/static/img/telegraf/controller-setup-owner-account.png differ diff --git a/static/img/telegraf/controller-transfer-ownership.png b/static/img/telegraf/controller-transfer-ownership.png new file mode 100644 index 000000000..2960654f4 Binary files /dev/null and b/static/img/telegraf/controller-transfer-ownership.png differ