diff --git a/.betterer.results b/.betterer.results index 89f038771ec..eedd45faab7 100644 --- a/.betterer.results +++ b/.betterer.results @@ -540,9 +540,6 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] ], - "packages/grafana-ui/src/components/Combobox/Combobox.tsx:5381": [ - [0, 0, 0, "Do not use any type assertions.", "0"] - ], "packages/grafana-ui/src/components/Combobox/MultiCombobox.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] ], @@ -635,9 +632,6 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"] ], - "packages/grafana-ui/src/components/DateTimePickers/WeekStartPicker.tsx:5381": [ - [0, 0, 0, "Do not use any type assertions.", "0"] - ], "packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] ], @@ -3661,10 +3655,9 @@ exports[`better eslint`] = { [0, 0, 0, "Do not use any type assertions.", "1"], [0, 0, 0, "Do not use any type assertions.", "2"], [0, 0, 0, "Do not use any type assertions.", "3"], - [0, 0, 0, "Do not use any type assertions.", "4"], + [0, 0, 0, "Unexpected any. Specify a different type.", "4"], [0, 0, 0, "Unexpected any. Specify a different type.", "5"], - [0, 0, 0, "Unexpected any. Specify a different type.", "6"], - [0, 0, 0, "Unexpected any. Specify a different type.", "7"] + [0, 0, 0, "Unexpected any. Specify a different type.", "6"] ], "public/app/features/dashboard/api/v1.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] @@ -4991,12 +4984,7 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"] ], "public/app/features/expressions/components/Threshold.tsx:5381": [ - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] ], "public/app/features/expressions/guards.ts:5381": [ [0, 0, 0, "\'@grafana/runtime/src/utils/DataSourceWithBackend\' import is restricted from being used by a pattern. Import from the public export instead.", "0"], diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 90689b24a05..92581c315aa 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -757,6 +757,7 @@ embed.go @grafana/grafana-as-code /.github/workflows/add-to-whats-new.yml @grafana/docs-tooling /.github/workflows/auto-triager/ @grafana/plugins-platform-frontend /.github/workflows/alerting-swagger-gen.yml @grafana/alerting-backend +/.github/workflows/alerting-update-module.yml @grafana/alerting-backend /.github/workflows/auto-milestone.yml @grafana/grafana-developer-enablement-squad /.github/workflows/backport.yml @grafana/grafana-developer-enablement-squad /.github/workflows/bump-version.yml @grafana/grafana-developer-enablement-squad diff --git a/.github/workflows/alerting-update-module.yml b/.github/workflows/alerting-update-module.yml new file mode 100644 index 00000000000..eece934525e --- /dev/null +++ b/.github/workflows/alerting-update-module.yml @@ -0,0 +1,130 @@ +name: Update Alerting Module + +on: + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + update-grafana: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + + steps: + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2 + + - name: Check if update branch exists + run: | + if git ls-remote --heads origin update-alerting-module | grep -q 'update-alerting-module'; then + echo "Branch 'update-alerting-module' already exists. There might be an open PR with Grafana updates." + echo "Please review and merge/close the existing PR before running this workflow again." + exit 1 + fi + + - name: Setup Go + uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # 5.3.0 + with: + "go-version-file": "go.mod" + + - name: Extract current commit hash of alerting module + id: current-commit + run: | + FROM_COMMIT=$(go list -m -json github.com/grafana/alerting | jq -r '.Version' | grep -oP '(?<=-)[a-f0-9]+$') + echo "from_commit=$FROM_COMMIT" >> $GITHUB_OUTPUT + + - name: Get latest commit + id: latest-commit + env: + GH_TOKEN: ${{ github.token }} + run: | + TO_COMMIT=$(gh api repos/grafana/alerting/commits/main --jq '.sha') + if [ -z "$TO_COMMIT" ]; then + echo "Failed to fetch latest commit" + exit 1 + fi + echo "to_commit=$TO_COMMIT" >> $GITHUB_OUTPUT + + - name: Compare commit hashes + run: | + FROM_COMMIT="${{ steps.current-commit.outputs.from_commit }}" + TO_COMMIT="${{ steps.latest-commit.outputs.to_commit }}" + + # Compare just the length of the shorter hash + SHORT_TO_COMMIT="${TO_COMMIT:0:${#FROM_COMMIT}}" + + if [ "$FROM_COMMIT" = "$SHORT_TO_COMMIT" ]; then + echo "Current version ($FROM_COMMIT) is already at latest ($SHORT_TO_COMMIT). No update needed." + exit 0 + fi + echo "Updates available: $FROM_COMMIT -> $TO_COMMIT" + + - name: Check for commit history + id: check-commits + env: + GH_TOKEN: ${{ github.token }} + run: | + # get all commits that contains 'Alerting:' in the message + ALERTING_COMMITS=$(gh api repos/grafana/alerting/compare/${{ steps.current-commit.outputs.from_commit }}...${{ steps.latest-commit.outputs.to_commit }} \ + --jq '.commits[].commit.message | split("\n")[0]') || true + + # Use printf instead of echo -e for better multiline handling + printf "%s\n" "$ALERTING_COMMITS" + + # make the list for markdown and replace PR numbers with links + ALERTING_COMMITS_FORMATTED=$(echo "$ALERTING_COMMITS" | while read -r line; do echo "- $line" | sed -E 's/\(#([0-9]+)\)/[#\1](https:\/\/github.com\/grafana\/grafana\/pull\/\1)/g'; done) + + echo "alerting_commits<> $GITHUB_OUTPUT + echo "$ALERTING_COMMITS_FORMATTED" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + - name: Update alerting module + env: + GOSUMDB: off + run: | + go get github.com/grafana/alerting@${{ steps.latest-commit.outputs.to_commit }} + make update-workspace + + - id: get-secrets + uses: grafana/shared-workflows/actions/get-vault-secrets@28361cdb22223e5f1e34358c86c20908e7248760 # 1.1.0 + with: + repo_secrets: | + GITHUB_APP_ID=github-app:app-id + GITHUB_APP_PRIVATE_KEY=github-app:private-key + + - name: "Generate token" + id: generate_token + uses: actions/create-github-app-token@0d564482f06ca65fa9e77e2510873638c82206f2 # 1.11.5 + with: + app-id: ${{ env.GITHUB_APP_ID }} + private-key: ${{ env.GITHUB_APP_PRIVATE_KEY }} + + - name: Create Pull Request + uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # 7.0.6 + id: create-pr + with: + token: '${{ steps.generate_token.outputs.token }}' + title: 'Alerting: Update alerting module to ${{ steps.latest-commit.outputs.to_commit }}' + branch: alerting/update-alerting-module + delete-branch: true + body: | + Updates Grafana Alerting module to latest version. + + Compare changes: https://github.com/grafana/alerting/compare/${{ steps.current-commit.outputs.from_commit }}...${{ steps.latest-commit.outputs.to_commit }} +
+ Commits + + ${{ steps.check-commits.outputs.alerting_commits }} + +
+ + Created by: [GitHub Action Job](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) + - name: Add PR URL to Summary + if: steps.create-pr.outputs.pull-request-url != '' + run: | + echo "## Pull Request Created" >> $GITHUB_STEP_SUMMARY + echo "🔗 [View Pull Request](${{ steps.create-pr.outputs.pull-request-url }})" >> $GITHUB_STEP_SUMMARY \ No newline at end of file diff --git a/docs/sources/datasources/postgres/_index.md b/docs/sources/datasources/postgres/_index.md index 3489b760f70..868a2bb7d9e 100644 --- a/docs/sources/datasources/postgres/_index.md +++ b/docs/sources/datasources/postgres/_index.md @@ -2,7 +2,7 @@ aliases: - ../data-sources/postgres/ - ../features/datasources/postgres/ -description: Guide for using PostgreSQL in Grafana +description: Introduction to the PostgreSQL data source in Grafana. keywords: - grafana - postgresql @@ -16,506 +16,58 @@ menuTitle: PostgreSQL title: PostgreSQL data source weight: 1200 refs: - provisioning-data-sources: - - pattern: /docs/grafana/ - destination: /docs/grafana//administration/provisioning/#datasources - - pattern: /docs/grafana-cloud/ - destination: /docs/grafana//administration/provisioning/#datasources - variables: - - pattern: /docs/grafana/ - destination: /docs/grafana//dashboards/variables/ - - pattern: /docs/grafana-cloud/ - destination: /docs/grafana//dashboards/variables/ - add-template-variables-interval-ms: - - pattern: /docs/grafana/ - destination: /docs/grafana//dashboards/variables/add-template-variables/#__interval_ms - - pattern: /docs/grafana-cloud/ - destination: /docs/grafana//dashboards/variables/add-template-variables/#__interval_ms - add-template-variables-interval: - - pattern: /docs/grafana/ - destination: /docs/grafana//dashboards/variables/add-template-variables/#__interval - - pattern: /docs/grafana-cloud/ - destination: /docs/grafana//dashboards/variables/add-template-variables/#__interval annotate-visualizations: - pattern: /docs/grafana/ destination: /docs/grafana//dashboards/build-dashboards/annotate-visualizations/ - pattern: /docs/grafana-cloud/ destination: /docs/grafana//dashboards/build-dashboards/annotate-visualizations/ - configure-standard-options-display-name: + configure-postgres-data-source: - pattern: /docs/grafana/ - destination: /docs/grafana//panels-visualizations/configure-standard-options/#display-name + destination: /docs/grafana//datasources/postgres/configure/ - pattern: /docs/grafana-cloud/ - destination: /docs/grafana//panels-visualizations/configure-standard-options/#display-name - data-source-management: + destination: /docs/grafana//datasources/postgres/configure/ + postgres-query-editor: - pattern: /docs/grafana/ - destination: /docs/grafana//administration/data-source-management/ + destination: /docs/grafana//datasources/postgres/query-editor/ - pattern: /docs/grafana-cloud/ - destination: /docs/grafana//administration/data-source-management/ - variable-syntax-advanced-variable-format-options: + destination: /docs/grafana//datasources/postgres/query-editor/ + alerting: - pattern: /docs/grafana/ - destination: /docs/grafana//dashboards/variables/variable-syntax/#advanced-variable-format-options + destination: /docs/grafana//alerting/ - pattern: /docs/grafana-cloud/ - destination: /docs/grafana//dashboards/variables/variable-syntax/#advanced-variable-format-options + destination: /docs/grafana-cloud/alerting-and-irm/alerting/ + transformations: + - pattern: /docs/grafana/ + destination: /docs/grafana//panels-visualizations/query-transform-data/transform-data/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana-cloud/visualizations/panels-visualizations/query-transform-data/transform-data/ + visualizations: + - pattern: /docs/grafana/ + destination: /docs/grafana//panels-visualizations/visualizations/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/ --- # PostgreSQL data source -Grafana ships with a built-in PostgreSQL data source plugin that allows you to query and visualize data from a PostgreSQL compatible database. +Grafana includes a built-in PostgreSQL data source plugin, enabling you to query and visualize data from any PostgreSQL-compatible database. You don't need to install a plugin to add the PostgreSQL data source to your Grafana instance. -For instructions on how to add a data source to Grafana, refer to the [administration documentation](ref:data-source-management). -Only users with the organization administrator role can add data sources. -Administrators can also [configure the data source via YAML](#provision-the-data-source) with Grafana's provisioning system. +Grafana offers several configuration options for this data source as well as a visual and code-based query editor. + +## Get started with the PostgreSQL data source + +The following documents will help you get started with the PostgreSQL data source in Grafana: + +- [Configure the PostgreSQL data source](ref:configure-postgres-data-source) +- [PostgreSQL query editor](ref:postgres-query-editor) + +After you have configured the data source you can: + +- Create a variety of [visualizations](ref:visualizations) +- Add [annotations](ref:annotate-visualizations) +- Set up [alerting](ref:alerting) +- Add [transformations](ref:transformations) + +View a PostgreSQL overview on Grafana Play: {{< docs/play title="PostgreSQL Overview" url="https://play.grafana.org/d/ddvpgdhiwjvuod/postgresql-overview" >}} - -## PostgreSQL settings - -To configure basic settings for the data source, complete the following steps: - -1. Click **Connections** in the left-side menu. -1. Under Your connections, click **Data sources**. -1. Enter `PostgreSQL` in the search bar. -1. Select **PostgreSQL**. - - The **Settings** tab of the data source is displayed. - -1. Set the data source's basic configuration options: - -| Name | Description | -| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Name** | The data source name. This is how you refer to the data source in panels and queries. | -| **Default** | Default data source means that it will be pre-selected for new panels. | -| **Host** | The IP address/hostname and optional port of your PostgreSQL instance. _Do not_ include the database name. The connection string for connecting to Postgres will not be correct and it may cause errors. | -| **Database** | Name of your PostgreSQL database. | -| **User** | Database user's login/username | -| **Password** | Database user's password | -| **SSL Mode** | Determines whether or with what priority a secure SSL TCP/IP connection will be negotiated with the server. When SSL Mode is disabled, SSL Method and Auth Details would not be visible. | -| **SSL Auth Details Method** | Determines whether the SSL Auth details will be configured as a file path or file content. | -| **SSL Auth Details Value** | File path or file content of SSL root certificate, client certificate and client key | -| **Max open** | The maximum number of open connections to the database, default `100`. | -| **Max idle** | The maximum number of connections in the idle connection pool, default `100`. | -| **Auto (max idle)** | If set will set the maximum number of idle connections to the number of maximum open connections. Default is `true`. | -| **Max lifetime** | The maximum amount of time in seconds a connection may be reused, default `14400`/4 hours. | -| **Version** | Determines which functions are available in the query builder. | -| **TimescaleDB** | A time-series database built as a PostgreSQL extension. When enabled, Grafana uses `time_bucket` in the `$__timeGroup` macro to display TimescaleDB specific aggregate functions in the query builder. For more information, see [TimescaleDB documentation](https://docs.timescale.com/timescaledb/latest/tutorials/grafana/grafana-timescalecloud/#connect-timescaledb-and-grafana). | - -### Min time interval - -A lower limit for the [`$__interval`](ref:add-template-variables-interval) and [`$__interval_ms`](ref:add-template-variables-interval-ms) variables. -Recommended to be set to write frequency, for example `1m` if your data is written every minute. -This option can also be overridden/configured in a dashboard panel under data source options. It's important to note that this value **needs** to be formatted as a -number followed by a valid time identifier, e.g. `1m` (1 minute) or `30s` (30 seconds). The following time identifiers are supported: - -| Identifier | Description | -| ---------- | ----------- | -| `y` | year | -| `M` | month | -| `w` | week | -| `d` | day | -| `h` | hour | -| `m` | minute | -| `s` | second | -| `ms` | millisecond | - -### Database user permissions (Important!) - -The database user you specify when you add the data source should only be granted SELECT permissions on -the specified database and tables you want to query. Grafana does not validate that the query is safe. The query -could include any SQL statement. For example, statements like `DELETE FROM user;` and `DROP TABLE user;` would be -executed. To protect against this we **highly** recommend you create a specific PostgreSQL user with restricted permissions. - -Example: - -```sql - CREATE USER grafanareader WITH PASSWORD 'password'; - GRANT USAGE ON SCHEMA schema TO grafanareader; - GRANT SELECT ON schema.table TO grafanareader; -``` - -Make sure the user does not get any unwanted privileges from the public role. - -## Query builder - -{{< figure src="/static/img/docs/screenshot-postgres-query-editor.png" class="docs-image--no-shadow" caption="PostgreSQL query builder" >}} - -The PostgreSQL query builder is available when editing a panel using a PostgreSQL data source. The built query can be run by pressing the `Run query` button in the top right corner of the editor. - -### Format - -The response from PostgreSQL can be formatted as either a table or as a time series. To use the time series format one of the columns must be named `time`. - -### Dataset and table selection - -The dataset dropdown will be populated with the configured database to which the user has access. -The table dropdown is populated with the tables that are available within that database. - -### Columns and Aggregation functions (SELECT) - -Using the dropdown, select a column to include in the data. You can also specify an optional aggregation function. - -Add further value columns by clicking the plus button and another column dropdown appears. - -{{< docs/shared source="grafana" lookup="datasources/sql-query-builder-macros.md" version="" >}} - -### Filter data (WHERE) - -To add a filter, toggle the **Filter** switch at the top of the editor. -This reveals a **Filter by column value** section with two dropdown selectors. - -Use the first dropdown to choose whether all of the filters need to match (`AND`), or if only one of the filters needs to match (`OR`). -Use the second dropdown to choose a filter. - -To filter on more columns, click the plus (`+`) button to the right of the condition dropdown. - -To remove a filter, click the `x` button next to that filter's dropdown. - -After selecting a date type column, you can choose Macros from the operators list and select timeFilter which will add the $\_\_timeFilter macro to the query with the selected date column. - -### Group By - -To group the results by column, flip the group switch at the top of the editor. You can then choose which column to group the results by. The group by clause can be removed by pressing the X button. - -### Preview - -By flipping the preview switch at the top of the editor, you can get a preview of the SQL query generated by the query builder. - -### Provision the data source - -It's now possible to configure data sources using config files with Grafana's provisioning system. You can read more about how it works and all the settings you can set for data sources on the [provisioning docs page](ref:provisioning-data-sources). - -#### Provisioning example - -```yaml -apiVersion: 1 - -datasources: - - name: Postgres - type: postgres - url: localhost:5432 - user: grafana - secureJsonData: - password: 'Password!' - jsonData: - database: grafana - sslmode: 'disable' # disable/require/verify-ca/verify-full - maxOpenConns: 100 - maxIdleConns: 100 - maxIdleConnsAuto: true - connMaxLifetime: 14400 - postgresVersion: 903 # 903=9.3, 904=9.4, 905=9.5, 906=9.6, 1000=10 - timescaledb: false -``` - -{{% admonition type="note" %}} -In the above code, the `postgresVersion` value of `10` refers to version PostgreSQL 10 and above. -{{% /admonition %}} - -#### Troubleshoot provisioning - -If you encounter metric request errors or other issues: - -- Make sure your data source YAML file parameters exactly match the example. This includes parameter names and use of quotation marks. -- Make sure the `database` name is not included in the `url`. - -## Code editor - -{{< figure src="/static/img/docs/v92/sql_code_editor.png" class="docs-image--no-shadow" >}} - -To make advanced queries, switch to the code editor by clicking `code` in the top right corner of the editor. The code editor support autocompletion of tables, columns, SQL keywords, standard sql functions, Grafana template variables and Grafana macros. Columns cannot be completed before a table has been specified. - -You can expand the code editor by pressing the `chevron` pointing downwards in the lower right corner of the code editor. - -`CTRL/CMD + Return` works as a keyboard shortcut to run the query. - -## Macros - -Macros can be used within a query to simplify syntax and allow for dynamic parts. - -| Macro example | Description | -| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `$__time(dateColumn)` | Will be replaced by an expression to convert to a UNIX timestamp and rename the column to `time_sec`. For example, _UNIX_TIMESTAMP(dateColumn) as time_sec_ | -| `$__timeEpoch(dateColumn)` | Will be replaced by an expression to convert to a UNIX timestamp and rename the column to `time_sec`. For example, _UNIX_TIMESTAMP(dateColumn) as time_sec_ | -| `$__timeFilter(dateColumn)` | Will be replaced by a time range filter using the specified column name. For example, _dateColumn BETWEEN FROM_UNIXTIME(1494410783) AND FROM_UNIXTIME(1494410983)_ | -| `$__timeFrom()` | Will be replaced by the start of the currently active time selection. For example, _FROM_UNIXTIME(1494410783)_ | -| `$__timeTo()` | Will be replaced by the end of the currently active time selection. For example, _FROM_UNIXTIME(1494410983)_ | -| `$__timeGroup(dateColumn,'5m')` | Will be replaced by an expression usable in GROUP BY clause. For example, *cast(cast(UNIX_TIMESTAMP(dateColumn)/(300) as signed)*300 as signed),\* | -| `$__timeGroup(dateColumn,'5m', 0)` | Same as above but with a fill parameter so missing points in that series will be added by grafana and 0 will be used as value (only works with time series queries). | -| `$__timeGroup(dateColumn,'5m', NULL)` | Same as above but NULL will be used as value for missing points (only works with time series queries). | -| `$__timeGroup(dateColumn,'5m', previous)` | Same as above but the previous value in that series will be used as fill value if no value has been seen yet NULL will be used (only works with time series queries). | -| `$__timeGroupAlias(dateColumn,'5m')` | Will be replaced identical to $\_\_timeGroup but with an added column alias. | -| `$__unixEpochFilter(dateColumn)` | Will be replaced by a time range filter using the specified column name with times represented as Unix timestamp. For example, _dateColumn > 1494410783 AND dateColumn < 1494497183_ | -| `$__unixEpochFrom()` | Will be replaced by the start of the currently active time selection as Unix timestamp. For example, _1494410783_ | -| `$__unixEpochTo()` | Will be replaced by the end of the currently active time selection as Unix timestamp. For example, _1494497183_ | -| `$__unixEpochNanoFilter(dateColumn)` | Will be replaced by a time range filter using the specified column name with times represented as nanosecond timestamp. For example, _dateColumn > 1494410783152415214 AND dateColumn < 1494497183142514872_ | -| `$__unixEpochNanoFrom()` | Will be replaced by the start of the currently active time selection as nanosecond timestamp. For example, _1494410783152415214_ | -| `$__unixEpochNanoTo()` | Will be replaced by the end of the currently active time selection as nanosecond timestamp. For example, _1494497183142514872_ | -| `$__unixEpochGroup(dateColumn,'5m', [fillmode])` | Same as $\_\_timeGroup but for times stored as Unix timestamp (`fillMode` only works with time series queries). | -| `$__unixEpochGroupAlias(dateColumn,'5m', [fillmode])` | Same as above but also adds a column alias (`fillMode` only works with time series queries). | - -## Table queries - -If the `Format as` query option is set to `Table` then you can basically do any type of SQL query. The table panel will automatically show the results of whatever columns and rows your query returns. - -Query editor with example query: - -![](/static/img/docs/v46/postgres_table_query.png) - -The query: - -```sql -SELECT - title as "Title", - "user".login as "Created By", - dashboard.created as "Created On" -FROM dashboard -INNER JOIN "user" on "user".id = dashboard.created_by -WHERE $__timeFilter(dashboard.created) -``` - -You can control the name of the Table panel columns by using regular `as ` SQL column selection syntax. - -The resulting table panel: - -![postgres table](/static/img/docs/v46/postgres_table.png) - -## Time series queries - -If you set Format as to _Time series_, then the query must have a column named time that returns either a SQL datetime or any numeric datatype representing Unix epoch in seconds. In addition, result sets of time series queries must be sorted by time for panels to properly visualize the result. - -A time series query result is returned in a [wide data frame format](https://grafana.com/developers/plugin-tools/key-concepts/data-frames#wide-format). Any column except time or of type string transforms into value fields in the data frame query result. Any string column transforms into field labels in the data frame query result. - -> For backward compatibility, there's an exception to the above rule for queries that return three columns including a string column named metric. Instead of transforming the metric column into field labels, it becomes the field name, and then the series name is formatted as the value of the metric column. See the example with the metric column below. - -To optionally customize the default series name formatting, refer to [Standard options definitions](ref:configure-standard-options-display-name). - -**Example with `metric` column:** - -```sql -SELECT - $__timeGroupAlias("time_date_time",'5m'), - min("value_double"), - 'min' as metric -FROM test_data -WHERE $__timeFilter("time_date_time") -GROUP BY time -ORDER BY time -``` - -Data frame result: - -```text -+---------------------+-----------------+ -| Name: time | Name: min | -| Labels: | Labels: | -| Type: []time.Time | Type: []float64 | -+---------------------+-----------------+ -| 2020-01-02 03:05:00 | 3 | -| 2020-01-02 03:10:00 | 6 | -+---------------------+-----------------+ -``` - -**Example using the fill parameter in the $\_\_timeGroupAlias macro to convert null values to be zero instead:** - -```sql -SELECT - $__timeGroupAlias("createdAt",'5m',0), - sum(value) as value, - hostname -FROM test_data -WHERE - $__timeFilter("createdAt") -GROUP BY time, hostname -ORDER BY time -``` - -Given the data frame result in the following example and using the graph panel, you will get two series named _value 10.0.1.1_ and _value 10.0.1.2_. To render the series with a name of _10.0.1.1_ and _10.0.1.2_ , use a [Standard options definitions](ref:configure-standard-options-display-name) display value of `${__field.labels.hostname}`. - -Data frame result: - -```text -+---------------------+---------------------------+---------------------------+ -| Name: time | Name: value | Name: value | -| Labels: | Labels: hostname=10.0.1.1 | Labels: hostname=10.0.1.2 | -| Type: []time.Time | Type: []float64 | Type: []float64 | -+---------------------+---------------------------+---------------------------+ -| 2020-01-02 03:05:00 | 3 | 4 | -| 2020-01-02 03:10:00 | 6 | 7 | -+---------------------+---------------------------+---------------------------+ -``` - -**Example with multiple columns:** - -```sql -SELECT - $__timeGroupAlias("time_date_time",'5m'), - min("value_double") as "min_value", - max("value_double") as "max_value" -FROM test_data -WHERE $__timeFilter("time_date_time") -GROUP BY time -ORDER BY time -``` - -Data frame result: - -```text -+---------------------+-----------------+-----------------+ -| Name: time | Name: min_value | Name: max_value | -| Labels: | Labels: | Labels: | -| Type: []time.Time | Type: []float64 | Type: []float64 | -+---------------------+-----------------+-----------------+ -| 2020-01-02 03:04:00 | 3 | 4 | -| 2020-01-02 03:05:00 | 6 | 7 | -+---------------------+-----------------+-----------------+ -``` - -## Templating - -Instead of hard-coding things like server, application and sensor name in your metric queries you can use variables in their place. Variables are shown as dropdown select boxes at the top of the dashboard. These dropdowns make it easy to change the data being displayed in your dashboard. - -Refer to [Templates and variables](ref:variables) for an introduction to the templating feature and the different types of template variables. - -### Query variable - -If you add a template variable of the type `Query`, you can write a PostgreSQL query that can -return things like measurement names, key names or key values that are shown as a dropdown select box. - -For example, you can have a variable that contains all values for the `hostname` column in a table if you specify a query like this in the templating variable _Query_ setting. - -```sql -SELECT hostname FROM host -``` - -A query can return multiple columns and Grafana will automatically create a list from them. For example, the query below will return a list with values from `hostname` and `hostname2`. - -```sql -SELECT host.hostname, other_host.hostname2 FROM host JOIN other_host ON host.city = other_host.city -``` - -To use time range dependent macros like `$__timeFilter(column)` in your query the refresh mode of the template variable needs to be set to _On Time Range Change_. - -```sql -SELECT event_name FROM event_log WHERE $__timeFilter(time_column) -``` - -Another option is a query that can create a key/value variable. The query should return two columns that are named `__text` and `__value`. The `__text` column value should be unique (if it is not unique then the first value is used). The options in the dropdown will have a text and value that allows you to have a friendly name as text and an id as the value. An example query with `hostname` as the text and `id` as the value: - -```sql -SELECT hostname AS __text, id AS __value FROM host -``` - -You can also create nested variables. Using a variable named `region`, you could have -the hosts variable only show hosts from the current selected region with a query like this (if `region` is a multi-value variable then use the `IN` comparison operator rather than `=` to match against multiple values): - -```sql -SELECT hostname FROM host WHERE region IN($region) -``` - -#### Using `__searchFilter` to filter results in Query Variable - -Using `__searchFilter` in the query field will filter the query result based on what the user types in the dropdown select box. -When nothing has been entered by the user the default value for `__searchFilter` is `%`. - -> Important that you surround the `__searchFilter` expression with quotes as Grafana does not do this for you. - -The example below shows how to use `__searchFilter` as part of the query field to enable searching for `hostname` while the user types in the dropdown select box. - -Query - -```sql -SELECT hostname FROM my_host WHERE hostname LIKE '$__searchFilter' -``` - -### Using Variables in Queries - -Template variable values are only quoted when the template variable is a `multi-value`. - -If the variable is a multi-value variable then use the `IN` comparison operator rather than `=` to match against multiple values. - -There are two syntaxes: - -`$` Example with a template variable named `hostname`: - -```sql -SELECT - atimestamp as time, - aint as value -FROM table -WHERE $__timeFilter(atimestamp) and hostname in($hostname) -ORDER BY atimestamp ASC -``` - -`[[varname]]` Example with a template variable named `hostname`: - -```sql -SELECT - atimestamp as time, - aint as value -FROM table -WHERE $__timeFilter(atimestamp) and hostname in([[hostname]]) -ORDER BY atimestamp ASC -``` - -#### Disabling quoting for multi-value variables - -Grafana automatically creates a quoted, comma-separated string for multi-value variables. For example: if `server01` and `server02` are selected then it will be formatted as: `'server01', 'server02'`. To disable quoting, use the csv formatting option for variables: - -`${servers:csv}` - -Read more about variable formatting options in the [Variables](ref:variable-syntax-advanced-variable-format-options) documentation. - -## Annotations - -[Annotations](ref:annotate-visualizations) allow you to overlay rich event information on top of graphs. You add annotation queries via the Dashboard menu / Annotations view. - -**Example query using time column with epoch values:** - -```sql -SELECT - epoch_time as time, - metric1 as text, - concat_ws(', ', metric1::text, metric2::text) as tags -FROM - public.test_data -WHERE - $__unixEpochFilter(epoch_time) -``` - -**Example region query using time and timeend columns with epoch values:** - -```sql -SELECT - epoch_time as time, - epoch_time_end as timeend, - metric1 as text, - concat_ws(', ', metric1::text, metric2::text) as tags -FROM - public.test_data -WHERE - $__unixEpochFilter(epoch_time) -``` - -**Example query using time column of native SQL date/time data type:** - -```sql -SELECT - native_date_time as time, - metric1 as text, - concat_ws(', ', metric1::text, metric2::text) as tags -FROM - public.test_data -WHERE - $__timeFilter(native_date_time) -``` - -| Name | Description | -| --------- | ----------------------------------------------------------------------------------------------------------------- | -| `time` | The name of the date/time field. Could be a column with a native SQL date/time data type or epoch value. | -| `timeend` | Optional name of the end date/time field. Could be a column with a native SQL date/time data type or epoch value. | -| `text` | Event description field. | -| `tags` | Optional field name to use for event tags as a comma separated string. | - -## Alerting - -Time series queries should work in alerting conditions. Table formatted queries are not yet supported in alert rule -conditions. diff --git a/docs/sources/datasources/postgres/configure/_index.md b/docs/sources/datasources/postgres/configure/_index.md new file mode 100644 index 00000000000..7b6a66c0a70 --- /dev/null +++ b/docs/sources/datasources/postgres/configure/_index.md @@ -0,0 +1,194 @@ +--- +description: This document provides instructions for configuring the PostgreSQL data source. +keywords: + - grafana + - postgresql + - guide +labels: + products: + - cloud + - enterprise + - oss +menuTitle: Configure the PostgreSQL data source +title: Configure the PostgreSQL data source +weight: 10 +refs: + provisioning-data-sources: + - pattern: /docs/grafana/ + destination: /docs/grafana//administration/provisioning/#datasources + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana//administration/provisioning/#datasources + variables: + - pattern: /docs/grafana/ + destination: /docs/grafana//dashboards/variables/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana//dashboards/variables/ + add-template-variables-interval-ms: + - pattern: /docs/grafana/ + destination: /docs/grafana//dashboards/variables/add-template-variables/#__interval_ms + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana//dashboards/variables/add-template-variables/#__interval_ms + add-template-variables-interval: + - pattern: /docs/grafana/ + destination: /docs/grafana//dashboards/variables/add-template-variables/#__interval + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana//dashboards/variables/add-template-variables/#__interval + data-source-management: + - pattern: /docs/grafana/ + destination: /docs/grafana//administration/data-source-management/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana//administration/data-source-management/ + variable-syntax-advanced-variable-format-options: + - pattern: /docs/grafana/ + destination: /docs/grafana//dashboards/variables/variable-syntax/#advanced-variable-format-options + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana//dashboards/variables/variable-syntax/#advanced-variable-format-options +--- + +# Configure the PostgreSQL data source + +This document provides instructions for configuring the PostgreSQL data source and explains available configuration options. For general information on managing data sources refer to [Data source management](ref:data-source-management). + +## Before you begin + +You must have the `Organization administrator` role to configure the Postgres data source. +Organization administrators can also [configure the data source via YAML](#provision-the-data-source) with the Grafana provisioning system. + +Grafana comes with a built-in PostgreSQL data source plugin, eliminating the need to install a plugin. + +{{< admonition type="note" >}} +When adding a data source, the database user you specify should have only `SELECT` permissions on the relevant database and tables. Grafana does not validate the safety of queries, which means they can include potentially harmful SQL statements, such as `USE otherdb;` or `DROP TABLE user;`, that could be executed. To mitigate this risk, Grafana strongly recommends creating a dedicated PostgreSQL user with restricted permissions. +{{< /admonition >}} + +Example: + +```sql + CREATE USER grafanareader WITH PASSWORD 'password'; + GRANT USAGE ON SCHEMA schema TO grafanareader; + GRANT SELECT ON schema.table TO grafanareader; +``` + +## Add the PostgreSQL data source + +Complete the following steps to set up a new PostgreSQL data source: + +1. Click **Connections** in the left-side menu. +1. Click **Add new connection** +1. Type `PostgreSQL` in the search bar. +1. Select the **PostgreSQL data source**. +1. Click **Add new data source** in the upper right. + +You are taken to the **Settings** tab where you will configure the data source. + +## PostgreSQL configuration options + +Following is a list of PostgreSQL configuration options: + +- **Name** - Sets the name you use to refer to the data source in panels and queries. Examples: `PostgreSQL-DB-1`. +- **Default** - Toggle to set this specific PostgreSQL data source as the default pre-selected data source in panels and visualizations. + +**Connection section:** + +- **Host URL** - The IP address/hostname and optional port of your PostgreSQL instance. +- **Database name** - The name of your PostgreSQL database. + +**Authentication section:** + +- **Username** - Enter the username used to connect to your PostgreSQL database. +- **Password** - Enter the password used to connect to the PostgreSQL database. +- **TLS/SSL Mode** - Determines whether or with what priority a secure SSL TCP/IP connection will be negotiated with the server. When **TLS/SSL Mode** is disabled, **TLS/SSL Method** and **TLS/SSL Auth Details** aren't visible options. +- **TLS/SSL Method** - Determines how TLS/SSL certificates are configured. + - **File system path** - This option allows you to configure certificates by specifying paths to existing certificates on the local file system where Grafana is running. Ensure this file is readable by the user executing the Grafana process. + - **Certificate content** - This option allows you to configure certificate by specifying their content. The content is stored and encrypted in the Grafana database. When connecting to the database, the certificates are saved as files, on the local filesystem, in the Grafana data path. + +**TLS/SSL Auth Details** + +If you select the TLS/SSL Mode options **require**, **verify-ca** or **verify-full** and **file system path** the following are required: + +- **TLS/SSL Root Certificate** - Specify the path to the root certificate file. +- **TLS/SSL Client Certificate** - Specify the path to the client certificate and ensure the file is accessible to the user running the Grafana process. +- **TLS/SSL Client Key** - Specify the path to the client key file and ensure the file is accessible to the user running the Grafana process. + +If you select the TLS/SSL Mode option **require** and TLS/SSL Method certificate content the following are required: + +- **TLS/SSL Client Certificate** - Provide the client certificate. +- **TLS/SSL Client Key** - Provide the client key. + +If you select the TLS/SSL Mode options **verify-ca** or **verify-full** with the TLS/SSL Method certificate content the following are required: + +- **TLS/SSL Client Certificate** - Provide the client certificate. +- **TLS/SSL Root Certificate** - Provide the root certificate. +- **TLS/SSL Client Key** - Provide the client key. + +**PostgreSQL Options:** + +- **Version** - Determines which functions are available in the query builder. The default is the current version. +- **Min time interval** - Defines a lower limit for the auto group by by time interval. Grafana recommends aligning this setting with the data write frequency. For example, set it to `1m` if your data is written every minute. Refer to [Min time interval](#min-time-interval) for format examples. +- **TimescaleDB** - A time-series database built as a PostgreSQL extension. When enabled, Grafana uses `time_bucket` in the `$__timeGroup` macro to display TimescaleDB specific aggregate functions in the query builder. For more information, refer to [TimescaleDB documentation](https://docs.timescale.com/timescaledb/latest/tutorials/grafana/grafana-timescalecloud/#connect-timescaledb-and-grafana). + +**Connection limits:** + +- **Max open** - The maximum number of open connections to the database. The default `100`. +- **Auto max idle** - Toggle to set the maximum number of idle connections to the number of maximum open connections. This setting is toggled on by default. +- **Max idle** - The maximum number of connections in the idle connection pool. The default `100`. +- **Max lifetime** - The maximum amount of time in seconds a connection may be reused. The default is `14400`, or 4 hours. + +**Private data source connect** - _Only for Grafana Cloud users._ Private data source connect, or PDC, allows you to establish a private, secured connection between a Grafana Cloud instance, or stack, and data sources secured within a private network. Click the drop-down to locate the URL for PDC. For more information regarding Grafana PDC refer to [Private data source connect (PDC)](https://grafana.com/docs/grafana-cloud/connect-externally-hosted/private-data-source-connect/). + +Click **Manage private data source connect** to be taken to your PDC connection page, where you’ll find your PDC configuration details. + +After you have added your PostgreSQL connection settings, click **Save & test** to test and save the data source connection. + +### Min time interval + +The **Min time interval** setting defines a lower limit for the [`$__interval`](ref:add-template-variables-interval) and [`$__interval_ms`](ref:add-template-variables-interval-ms) variables. + +This option can also be configured or overridden in the dashboard panel under the data source settings. + +This value must be formatted as a number followed by a valid time identifier: + +| Identifier | Description | +| ---------- | ----------- | +| `y` | year | +| `M` | month | +| `w` | week | +| `d` | day | +| `h` | hour | +| `m` | minute | +| `s` | second | +| `ms` | millisecond | + +## Provision the data source + +You can define and configure the data source in YAML files with [provisioning](/docs/grafana//administration/provisioning/#data-sources). +For more information about provisioning, and available configuration options, refer to [Provision Grafana](ref:provisioning-data-sources). + +### PostgreSQL provisioning example + +```yaml +apiVersion: 1 + +datasources: + - name: Postgres + type: postgres + url: localhost:5432 + user: grafana + secureJsonData: + password: 'Password!' + jsonData: + database: grafana + sslmode: 'disable' # disable/require/verify-ca/verify-full + maxOpenConns: 100 + maxIdleConns: 100 + maxIdleConnsAuto: true + connMaxLifetime: 14400 + postgresVersion: 903 # 903=9.3, 904=9.4, 905=9.5, 906=9.6, 1000=10 + timescaledb: false +``` + +#### Troubleshoot provisioning issues + +If you encounter metric request errors or other issues: + +- Ensure that the parameters in your data source YAML file precisely match the example provided, including parameter names and the correct use of quotation marks. +- Verify that the database name _isn't_ included in the URL. diff --git a/docs/sources/datasources/postgres/query-editor/_index.md b/docs/sources/datasources/postgres/query-editor/_index.md new file mode 100644 index 00000000000..5c37f7047e7 --- /dev/null +++ b/docs/sources/datasources/postgres/query-editor/_index.md @@ -0,0 +1,410 @@ +--- +description: This document describes the PostgreSQL query editor in Grafana. +keywords: + - grafana + - postgresql + - guide +labels: + products: + - cloud + - enterprise + - oss +menuTitle: PostgreSQL query editor +title: PostgreSQL query editor +weight: 20 +refs: + variables: + - pattern: /docs/grafana/ + destination: /docs/grafana//dashboards/variables/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana//dashboards/variables/ + add-template-variables-interval: + - pattern: /docs/grafana/ + destination: /docs/grafana//dashboards/variables/add-template-variables/#__interval + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana//dashboards/variables/add-template-variables/#__interval + explore: + - pattern: /docs/grafana/ + destination: /docs/grafana//explore/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana//explore/ + query-transform-data: + - pattern: /docs/grafana/ + destination: /docs/grafana//panels-visualizations/query-transform-data/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana-cloud/visualizations/panels-visualizations/query-transform-data/ + query-editor: + - pattern: /docs/grafana/ + destination: /docs/grafana//panels-visualizations/query-transform-data/#query-editors + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana-cloud/visualizations/panels-visualizations/query-transform-data/#query-editors + alert-rules: + - pattern: /docs/grafana/ + destination: /docs/grafana//alerting/fundamentals/alert-rules/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana-cloud/alerting-and-irm/alerting/alerting-rules/ + template-annotations-and-labels: + - pattern: /docs/grafana/ + destination: /docs/grafana//alerting/alerting-rules/templates/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana-cloud/alerting-and-irm/alerting/alerting-rules/templates/ + templates: + - pattern: /docs/grafana/ + destination: /docs/grafana//dashboards/variables/#templates + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana-cloud/visualizations/dashboards/variables/#templates +--- + +# PostgreSQL query editor + +Grafana query editors are unique for each data source. + +For general information on Grafana query editors, refer to [Query editors](ref:query-editor). + +For general information on querying data sources in Grafana, refer to [Query and transform data](ref:query-transform-data). + +The PostgreSQL query editor is located on the [Explore page](ref:explore). You can also access the PostgreSQL query editor from a dashboard panel. Click the ellipsis in the upper right of the panel and select **Edit**. + +{{< figure src="/static/img/docs/screenshot-postgres-query-editor.png" class="docs-image--no-shadow" caption="PostgreSQL query builder" >}} + +## PostgreSQL query editor components + +The PostgreSQL query editor has two modes: **Builder** and **Code**. + +Builder mode helps you build a query using a visual interface. Code mode allows for advanced querying and offers support for complex SQL query writing. + +### PostgreSQL Builder mode + +The following components will help you build a PostgreSQL query: + +- **Format** - Select a format response from the drop-down for the PostgreSQL query. The default is **Table**. If you use the **Time series** format option, one of the columns must be `time`. Refer to [Time series queries](#time-series-queries) for more information. +- **Table** - Select a table from the drop-down. Tables correspond to the chosen database. +- **Data operations** - _Optional_ Select an aggregation from the drop-down. You can add multiple data operations by clicking the **+ sign**. Click the **garbage can icon** to remove data operations. +- **Column** - Select a column on which to run the aggregation. +- **Alias** - _Optional_ Add an alias from the drop-down. You can also add your own alias by typing it in the box and clicking **Enter**. Remove an alias by clicking the **X**. +- **Filter** - Toggle to add filters. +- **Filter by column value** - _Optional_ If you toggle **Filter** you can add a column to filter by from the drop-down. To filter on more columns, click the **+ sign** to the right of the condition drop-down. You can choose a variety of operators from the drop-down next to the condition. When multiple filters are added you can add an `AND` operator to display all true conditions or an `OR` operator to display any true conditions. Use the second drop-down to choose a filter. To remove a filter, click the `X` button next to that filter's drop-down. After selecting a date type column, you can choose **Macros** from the operators list and select `timeFilter` which will add the `$\_\_timeFilter` macro to the query with the selected date column. +- **Group** - Toggle to add **Group by column**. +- **Group by column** - Select a column to filter by from the drop-down. Click the **+sign** to filter by multiple columns. Click the **X** to remove a filter. +- **Order** - Toggle to add an `ORDER BY` statement. +- **Order by** - Select a column to order by from the drop-down. Select ascending (`ASC`) or descending (`DESC`) order. +- **Limit** - You can add an optional limit on the number of retrieved results. Default is 50. +- **Preview** - Toggle for a preview of the SQL query generated by the query builder. Preview is toggled on by default. + +## PostgreSQL Code mode + +To create advanced queries, switch to **Code mode** by clicking **Code** in the upper right of the editor window. Code mode supports the auto-completion of tables, columns, SQL keywords, standard SQL functions, Grafana template variables, and Grafana macros. Columns cannot be completed before a table has been specified. + +{{< figure src="/static/img/docs/v92/sql_code_editor.png" class="docs-image--no-shadow" >}} + +Select **Table** or **Time Series** as the format. Click the **{}** in the bottom right to format the query. Click the **downward caret** to expand the Code mode editor. **CTRL/CMD + Return** serves as a keyboard shortcut to execute the query. + +{{< admonition type="warning" >}} +Changes made to a query in Code mode will not transfer to Builder mode and will be discarded. You will be prompted to copy your code to the clipboard to save any changes. +{{< /admonition >}} + +## Macros + +You can add macros to your queries to simplify the syntax and enable dynamic elements, such as date range filters. + +| Macro example | Description | +| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `$__time(dateColumn)` | Replaces the value with an expression to convert to a UNIX timestamp and renames the column to `time_sec`. Example: `UNIX_TIMESTAMP(dateColumn) AS time_sec`. | +| `$__timeEpoch(dateColumn)` | Replaces the value with an expression to convert to a UNIX Epoch timestamp and renames the column to `time_sec`. Example: `UNIX_TIMESTAMP(dateColumn) AS time_sec`. | +| `$__timeFilter(dateColumn)` | Replaces the value a time range filter using the specified column name. Example: `dateColumn BETWEEN FROM_UNIXTIME(1494410783) AND FROM_UNIXTIME(1494410983)` | +| `$__timeFrom()` | Replaces the value with the start of the currently active time selection. Example: `FROM_UNIXTIME(1494410783)` | +| `$__timeTo()` | Replaces the value with the end of the currently active time selection. Example: `FROM_UNIXTIME(1494410983)` | +| `$__timeGroup(dateColumn,'5m')` | Replaces the value with an expression suitable for use in a `GROUP BY` clause. Example: `cast(cast(UNIX_TIMESTAMP(dateColumn)/(300) AS signed)*300 AS signed)` | +| `$__timeGroup(dateColumn,'5m', 0)` | Same as the `$__timeGroup(dateColumn,'5m')` macro, but includes a fill parameter to ensure missing points in the series are added by Grafana, using 0 as the default value. **This applies only to time series queries.** | +| `$__timeGroup(dateColumn,'5m', NULL)` | Same as the `$__timeGroup(dateColumn,'5m', 0)` but `NULL` is used as the value for missing points. _This applies only to time series queries._ | +| `$__timeGroup(dateColumn,'5m', previous)` | Same as the `$__timeGroup(dateColumn,'5m', previous)` macro, but uses the previous value in the series as the fill value. If no previous value exists, it uses `NULL`. _This applies only to time series queries._ | +| `$__timeGroupAlias(dateColumn,'5m')` | Replaces the value identical to `$__timeGroup` but with an added column alias. | +| `$__unixEpochFilter(dateColumn)` | Replaces the value by a time range filter using the specified column name with times represented as a UNIX timestamp. Example: `dateColumn > 1494410783 AND dateColumn < 1494497183` | +| `$__unixEpochFrom()` | Replaces the value with the start of the currently active time selection as a UNIX timestamp. Example: `1494410783` | +| `$__unixEpochTo()` | Replaces the value with the end of the currently active time selection as a UNIX timestamp. Example: `1494497183` | +| `$__unixEpochNanoFilter(dateColumn)` | Replaces the value with a time range filter using the specified column name with time represented as a nanosecond timestamp. Example: `dateColumn > 1494410783152415214 AND dateColumn < 1494497183142514872` | +| `$__unixEpochNanoFrom()` | Replaces the value with the start of the currently active time selection as a nanosecond timestamp. Example: `1494410783152415214` | +| `$__unixEpochNanoTo()` | Replaces the value with the end of the currently active time selection as nanosecond timestamp. Example: `1494497183142514872` | +| `$__unixEpochGroup(dateColumn,'5m', [fillmode])` | Same as `$__timeGroup` but for times stored as Unix timestamp. `fillMode` only works with time series queries. | +| `$__unixEpochGroupAlias(dateColumn,'5m', [fillmode])` | Same as `$__timeGroup` but also adds a column alias. `fillMode` only works with time series queries. | + +## Table SQL queries + +If the **Format** option is set to **Table**, you can execute virtually any type of SQL query. The Table panel will automatically display the resulting columns and rows from your query. + +![Table query](/media/docs/postgres/PostgreSQL-query-editor-v11.4.png) + +You can change or customize the name of a Table panel column by using the SQL keyword `AS` syntax. + +```sql +SELECT + title as "Title", + "user".login as "Created By", + dashboard.created as "Created On" +FROM dashboard +INNER JOIN "user" on "user".id = dashboard.created_by +WHERE $__timeFilter(dashboard.created) +``` + +## Time series queries + +Set the **Format** option to **Time series** to create and run time series queries. + +{{< admonition type="note" >}} +To run a time series query you must include a column named `time` that returns either a SQL `datetime` value or a numeric datatype representing the UNIX epoch time in seconds. Additionally, the query results must be sorted by the `time` column for proper visualization in panels. +{{< /admonition >}} + +The examples in this section refer to the data in the following table: + +```text ++---------------------+--------------+---------------------+----------+ +| time_date_time | value_double | CreatedAt | hostname | ++---------------------+--------------+---------------------+----------+ +| 2020-01-02 03:05:00 | 3.0 | 2020-01-02 03:05:00 | 10.0.1.1 | +| 2020-01-02 03:06:00 | 4.0 | 2020-01-02 03:06:00 | 10.0.1.2 | +| 2020-01-02 03:10:00 | 6.0 | 2020-01-02 03:10:00 | 10.0.1.1 | +| 2020-01-02 03:11:00 | 7.0 | 2020-01-02 03:11:00 | 10.0.1.2 | +| 2020-01-02 03:20:00 | 5.0 | 2020-01-02 03:20:00 | 10.0.1.2 | ++---------------------+--------------+---------------------+----------+ +``` + +Time series query results are returned in [wide data frame format](https://grafana.com/developers/plugin-tools/key-concepts/data-frames#wide-format). In the data frame query result, any column, except for time or string-type columns, transforms into value fields. String columns, on the other hand, become field labels. + +{{< admonition type="note" >}} +For backward compatibility, an exception to this rule applies to queries that return three columns, one of which is a string column named `metric`. Instead of converting the metric column into field labels, it is used as the field name, while the series name is set to its value. See the following example for reference. +{{< /admonition >}} + +**Example with `metric` column:** + +```sql +SELECT + $__timeGroupAlias("time_date_time",'5m'), + min("value_double"), + 'min' as metric +FROM test_data +WHERE $__timeFilter("time_date_time") +GROUP BY time +ORDER BY time +``` + +Data frame result: + +```text ++---------------------+-----------------+ +| Name: time | Name: min | +| Labels: | Labels: | +| Type: []time.Time | Type: []float64 | ++---------------------+-----------------+ +| 2020-01-02 03:05:00 | 3 | +| 2020-01-02 03:10:00 | 6 | ++---------------------+-----------------+ +``` + +To customize default series name formatting, refer to [Standard options definitions](ref:configure-standard-options-display-name). + +Following are time series query examples. + +**Example using the fill parameter in the $\_\_timeGroupAlias macro to convert null values to be zero instead:** + +```sql +SELECT + $__timeGroupAlias("createdAt",'5m',0), + sum(value) as value, + hostname +FROM test_data +WHERE + $__timeFilter("createdAt") +GROUP BY time, hostname +ORDER BY time +``` + +Based on the data frame result in the following example, the time series panel will generate two series named _value 10.0.1.1_ and _value 10.0.1.2_. To display the series names as _10.0.1.1_ and _10.0.1.2_, use the [Standard options definitions](ref:configure-standard-options-display-name) display value `${__field.labels.hostname}`. + +Data frame result: + +```text ++---------------------+---------------------------+---------------------------+ +| Name: time | Name: value | Name: value | +| Labels: | Labels: hostname=10.0.1.1 | Labels: hostname=10.0.1.2 | +| Type: []time.Time | Type: []float64 | Type: []float64 | ++---------------------+---------------------------+---------------------------+ +| 2020-01-02 03:05:00 | 3 | 4 | +| 2020-01-02 03:10:00 | 6 | 7 | ++---------------------+---------------------------+---------------------------+ +``` + +**Example with multiple columns:** + +```sql +SELECT + $__timeGroupAlias("time_date_time",'5m'), + min("value_double") as "min_value", + max("value_double") as "max_value" +FROM test_data +WHERE $__timeFilter("time_date_time") +GROUP BY time +ORDER BY time +``` + +Data frame result: + +```text ++---------------------+-----------------+-----------------+ +| Name: time | Name: min_value | Name: max_value | +| Labels: | Labels: | Labels: | +| Type: []time.Time | Type: []float64 | Type: []float64 | ++---------------------+-----------------+-----------------+ +| 2020-01-02 03:04:00 | 3 | 4 | +| 2020-01-02 03:05:00 | 6 | 7 | ++---------------------+-----------------+-----------------+ +``` + +## Templating + +Instead of hard coding values like server, application, or sensor names in your metric queries, you can use variables. Variables appear as drop-down select boxes at the top of the dashboard. These drop-downs make it easy to change the data being displayed in your dashboard. + +Refer to [Templates](ref:templates) for an introduction to creating template variables as well as the different types. + +### Query variable + +If you add a `Query` template variable you can write a PostgreSQL query to retrieve items such as measurement names, key names, or key values, which will be displayed in the drop-down menu. + +For example, you can use a variable to retrieve all the values from the `hostname` column in a table by creating the following query in the templating variable _Query_ setting. + +```sql +SELECT hostname FROM host +``` + +A query can return multiple columns, and Grafana will automatically generate a list based on the query results. For example, the following query returns a list with values from `hostname` and `hostname2`. + +```sql +SELECT host.hostname, other_host.hostname2 FROM host JOIN other_host ON host.city = other_host.city +``` + +To use time range dependent macros like `$__timeFilter(column)` in your query, you must set the template variable's refresh mode to _On Time Range Change_. + +```sql +SELECT event_name FROM event_log WHERE $__timeFilter(time_column) +``` + +Another option is a query that can create a key/value variable. The query should return two columns that are named `__text` and `__value`. The `__text` column must contain unique values (if not, only the first value is used). This allows the drop-down options to display a text-friendly name as the text while using an ID as the value. For example, a query could use `hostname` as the text and `id` as the value: + +```sql +SELECT hostname AS __text, id AS __value FROM host +``` + +You can also create nested variables. For example, if you have a variable named `region`, you can configure the `hosts` variable to display only the hosts within the currently selected region as shown in the following example. If `region` is a multi-value variable, use the `IN` operator instead of `=` to match multiple values. + +```sql +SELECT hostname FROM host WHERE region IN($region) +``` + +#### Using `__searchFilter` to filter results in Query Variable + +Using `__searchFilter` in the query field allows the query results to be filtered based on the user’s input in the drop-down selection box. If you do not enter anything, the default value for `__searchFilter` is `%`. + +Note that you must enclose the `__searchFilter` expression in quotes as Grafana does not add them automatically. + +The following example demonstrates how to use `__searchFilter` in the query field to enable real-time searching for `hostname` as the user type in the drop-down selection box. + +```sql +SELECT hostname FROM my_host WHERE hostname LIKE '$__searchFilter' +``` + +### Using Variables in Queries + +Template variable values are only quoted when the template variable is a `multi-value`. + +If the variable is a multi-value variable, use the `IN` comparison operator instead of `=` to match against multiple values. + +You can use two different syntaxes: + +`$` Example with a template variable named `hostname`: + +```sql +SELECT + atimestamp as time, + aint as value +FROM table +WHERE $__timeFilter(atimestamp) and hostname in($hostname) +ORDER BY atimestamp ASC +``` + +`[[varname]]` Example with a template variable named `hostname`: + +```sql +SELECT + atimestamp as time, + aint as value +FROM table +WHERE $__timeFilter(atimestamp) and hostname in([[hostname]]) +ORDER BY atimestamp ASC +``` + +#### Disabling quoting for multi-value variables + +Grafana automatically formats multi-value variables as a quoted, comma-separated string. For example, if `server01` and `server02` are selected, they are formatted as `'server01'`, `'server02'`. To remove the quotes, enable the CSV formatting option for the variables: + +`${servers:csv}` + +Read more about variable formatting options in the [Variables](ref:variable-syntax-advanced-variable-format-options) documentation. + +## Annotations + +[Annotations](ref:annotate-visualizations) allow you to overlay rich event information on top of graphs. Add annotation queries via the **Dashboard settings > Annotations view**. + +**Example query using a `time` column with epoch values:** + +```sql +SELECT + epoch_time as time, + metric1 as text, + concat_ws(', ', metric1::text, metric2::text) as tags +FROM + public.test_data +WHERE + $__unixEpochFilter(epoch_time) +``` + +**Example region query using `time` and `timeend` columns with epoch values:** + +```sql +SELECT + epoch_time as time, + epoch_time_end as timeend, + metric1 as text, + concat_ws(', ', metric1::text, metric2::text) as tags +FROM + public.test_data +WHERE + $__unixEpochFilter(epoch_time) +``` + +**Example query using a `time` column with a native SQL date/time data type:** + +```sql +SELECT + native_date_time as time, + metric1 as text, + concat_ws(', ', metric1::text, metric2::text) as tags +FROM + public.test_data +WHERE + $__timeFilter(native_date_time) +``` + +| Name | Description | +| --------- | --------------------------------------------------------------------------------------------------------------------- | +| `time` | The name of the date/time field, which can be a column with a native SQL date/time data type or epoch value. | +| `timeend` | Optional name of the end date/time field, which can be a column with a native SQL date/time data type or epoch value. | +| `text` | Event description field. | +| `tags` | Optional field name to use for event tags as a comma-separated string. | + +## Alerting + +Use time series queries to create alerts. Table formatted queries aren't yet supported in alert rule conditions. + +For more information regarding alerting refer to the following: + +- [Alert rules](ref:alert-rules) +- [Template annotations and labels](ref:template-annotations-and-labels) diff --git a/docs/sources/explore/simplified-exploration/_index.md b/docs/sources/explore/simplified-exploration/_index.md index bf43b04d41e..360b37aee5a 100644 --- a/docs/sources/explore/simplified-exploration/_index.md +++ b/docs/sources/explore/simplified-exploration/_index.md @@ -12,7 +12,7 @@ hero: level: 1 width: 100 height: 100 - description: Use the Drilldown apps to investigate and identify issues using telemetry data. + description: Use the Grafana Drilldown apps to investigate and identify issues using telemetry data. cards: title_class: pt-0 lh-1 items: @@ -40,6 +40,8 @@ The Grafana Drilldown apps are designed for effortless data exploration through Easily explore telemetry signals with these specialized tools, tailored specifically for the Grafana databases to provide quick and accurate insights. +{{< docs/shared source="grafana" lookup="plugins/rename-note.md" version="" >}} + To learn more, read: - [From multi-line queries to no-code investigations: meeting Grafana users where they are](https://grafana.com/blog/2024/10/22/from-multi-line-queries-to-no-code-investigations-meeting-grafana-users-where-they-are/) diff --git a/docs/sources/explore/simplified-exploration/metrics/index.md b/docs/sources/explore/simplified-exploration/metrics/index.md index a9d5d291772..eb6d23509e5 100644 --- a/docs/sources/explore/simplified-exploration/metrics/index.md +++ b/docs/sources/explore/simplified-exploration/metrics/index.md @@ -16,7 +16,9 @@ weight: 200 Grafana Metrics Drilldown is a query-less experience for browsing **Prometheus-compatible** metrics. Quickly find related metrics with just a few simple clicks, without needing to write PromQL queries to retrieve metrics. -With Grafana Metrics Drilldown, you can: +{{< docs/shared source="grafana" lookup="plugins/rename-note.md" version="" >}} + +With Metrics Drilldown, you can: - Easily segment metrics based on their labels, so you can immediately spot anomalies and identify issues. - Automatically display the optimal visualization for each metric type (gauge vs. counter, for example) without manual setup. @@ -25,13 +27,13 @@ With Grafana Metrics Drilldown, you can: - View a history of user steps when navigating through metrics and their filters. - Seamlessly pivot to related telemetry, including log data. -{{< docs/play title="Grafana Metrics Drilldown" url="https://play.grafana.org/explore/metrics/trail?from=now-1h&to=now&var-ds=grafanacloud-demoinfra-prom&var-filters=&refresh=&metricPrefix=all" >}} +{{< docs/play title="Metrics Drilldown" url="https://play.grafana.org/explore/metrics/trail?from=now-1h&to=now&var-ds=grafanacloud-demoinfra-prom&var-filters=&refresh=&metricPrefix=all" >}} -You can access Grafana Metrics Drilldown either as a standalone experience or as part of Grafana dashboards. +You can access Metrics Drilldown either as a standalone experience or as part of Grafana dashboards. ## Standalone experience -To access Grafana Metrics Drilldown as a standalone experience: +To access Metrics Drilldown as a standalone experience: 1. Click the arrow next to **Drilldown** in the Grafana left-side menu and click **Metrics**. You are taken to an overview page that shows recent metrics, bookmarks, and the option to select a new metric exploration. 1. To get started with a new exploration, click **Let's start!**. @@ -63,7 +65,7 @@ After you have gathered your metrics exploration data you can: ## Dashboard experience -To access Grafana Metrics Drilldown via a dashboard: +To access Metrics Drilldown via a dashboard: 1. Navigate to your dashboard. 1. Select a time series panel. diff --git a/docs/sources/shared/plugins/rename-note.md b/docs/sources/shared/plugins/rename-note.md new file mode 100644 index 00000000000..5eaa9a1adf4 --- /dev/null +++ b/docs/sources/shared/plugins/rename-note.md @@ -0,0 +1,19 @@ +--- +headless: true +labels: + products: + - enterprise + - oss +--- + +[//]: # 'This file contains a rename note for Explore to Drilldown apps.' +[//]: # 'This shared file is included in a lot of files. Check the app docs in' +[//]: # 'drilldown-traces, drilldown-logs, drilldown-profiles, grafana, and website/grafana-cloud.' +[//]: # 'If you make changes to this file, verify that the meaning and content are not changed in any place where the file is included.' +[//]: # 'Any links should be fully qualified and not relative: /docs/grafana/ instead of ../grafana/.' + +{{< admonition type="note" >}} +The Grafana Explore apps have changed to Grafana Drilldown apps. +For example, Explore Logs is now Logs Drilldown. +To learn more, read [Grafana Drilldown apps: the improved queryless experience known as the Explore apps](https://grafana.com/blog/2025/02/20/grafana-drilldown-apps-the-improved-queryless-experience-formerly-known-as-the-explore-apps/). +{{< /admonition >}} diff --git a/e2e/dashboards-suite/utils/makeDashboard.ts b/e2e/dashboards-suite/utils/makeDashboard.ts index 4deaaa773ce..2ada48db7a9 100644 --- a/e2e/dashboards-suite/utils/makeDashboard.ts +++ b/e2e/dashboards-suite/utils/makeDashboard.ts @@ -48,8 +48,8 @@ export function makeNewDashboardRequestBody(dashboardName: string, folderUid?: s timezone: '', title: dashboardName, version: 0, - weekStart: '', uid: '', + weekStart: '', }, message: '', overwrite: false, diff --git a/go.mod b/go.mod index 8e2e1792445..d512579c149 100644 --- a/go.mod +++ b/go.mod @@ -54,7 +54,7 @@ require ( github.com/go-openapi/runtime v0.28.0 // @grafana/alerting-backend github.com/go-openapi/strfmt v0.23.0 // @grafana/alerting-backend github.com/go-redis/redis/v8 v8.11.5 // @grafana/grafana-backend-group - github.com/go-sourcemap/sourcemap v2.1.3+incompatible // @grafana/grafana-backend-group + github.com/go-sourcemap/sourcemap v2.1.4+incompatible // @grafana/grafana-backend-group github.com/go-sql-driver/mysql v1.8.1 // @grafana/grafana-search-and-storage github.com/go-stack/stack v1.8.1 // @grafana/grafana-backend-group github.com/gobwas/glob v0.2.3 // @grafana/grafana-backend-group @@ -71,7 +71,7 @@ require ( github.com/googleapis/gax-go/v2 v2.14.1 // @grafana/grafana-backend-group github.com/gorilla/mux v1.8.1 // @grafana/grafana-backend-group github.com/gorilla/websocket v1.5.3 // @grafana/grafana-app-platform-squad - github.com/grafana/alerting v0.0.0-20250219153626-c475b1a572b0 // @grafana/alerting-backend + github.com/grafana/alerting v0.0.0-20250221202230-9d7e00921e44 // @grafana/alerting-backend github.com/grafana/authlib v0.0.0-20250219100139-6a3b1bbb50e7 // @grafana/identity-access-team github.com/grafana/authlib/types v0.0.0-20250219092154-21ce22b49f31 // @grafana/identity-access-team github.com/grafana/dataplane/examples v0.0.1 // @grafana/observability-metrics @@ -111,7 +111,6 @@ require ( github.com/jmoiron/sqlx v1.3.5 // @grafana/grafana-backend-group github.com/json-iterator/go v1.1.12 // @grafana/grafana-backend-group github.com/lib/pq v1.10.9 // @grafana/grafana-backend-group - github.com/linkedin/goavro/v2 v2.10.0 // @grafana/grafana-backend-group github.com/m3db/prometheus_remote_client_golang v0.4.4 // @grafana/grafana-backend-group github.com/madflojo/testcerts v1.1.1 // @grafana/alerting-backend github.com/magefile/mage v1.15.0 // @grafana/grafana-developer-enablement-squad diff --git a/go.sum b/go.sum index 88780f81fc9..2b409ed61b5 100644 --- a/go.sum +++ b/go.sum @@ -1281,8 +1281,8 @@ github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-resty/resty/v2 v2.15.3 h1:bqff+hcqAflpiF591hhJzNdkRsFhlB96CYfBwSFvql8= github.com/go-resty/resty/v2 v2.15.3/go.mod h1:0fHAoK7JoBy/Ch36N8VFeMsK7xQOHhvWaC3iOktwmIU= -github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= -github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= +github.com/go-sourcemap/sourcemap v2.1.4+incompatible h1:a+iTbH5auLKxaNwQFg0B+TCYl6lbukKPc7b5x0n1s6Q= +github.com/go-sourcemap/sourcemap v2.1.4+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -1511,8 +1511,8 @@ github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7Fsg github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grafana/alerting v0.0.0-20250219153626-c475b1a572b0 h1:LGH+tVzHCDrR9hsltmkP4jmNRg5IreQw5CNFbJKlnts= -github.com/grafana/alerting v0.0.0-20250219153626-c475b1a572b0/go.mod h1:hdGB3dSl8Ma9Rjo2YiAEAjMkZ5HiNJbNDqRKDefRZrM= +github.com/grafana/alerting v0.0.0-20250221202230-9d7e00921e44 h1:vboqvbAO0s0CTALHnqfmNvhCP1ziBcZNpYDbORqvOgg= +github.com/grafana/alerting v0.0.0-20250221202230-9d7e00921e44/go.mod h1:hdGB3dSl8Ma9Rjo2YiAEAjMkZ5HiNJbNDqRKDefRZrM= github.com/grafana/authlib v0.0.0-20250219100139-6a3b1bbb50e7 h1:NTMmow+74I3Jb033xhbRgWQS7A//5TDhiM4tl7bsVP4= github.com/grafana/authlib v0.0.0-20250219100139-6a3b1bbb50e7/go.mod h1:T3X4z0ejGfJOiOmZLFeKCRT/yxWJq/RtclAc/PHj/w4= github.com/grafana/authlib/types v0.0.0-20250219092154-21ce22b49f31 h1:EokLC5grHwLPs4tXW8T6E8187H1e5G9AP0QQ5B60HbA= @@ -1845,8 +1845,6 @@ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/linkedin/goavro/v2 v2.10.0 h1:eTBIRoInBM88gITGXYtUSqqxLTFXfOsJBiX8ZMW0o4U= -github.com/linkedin/goavro/v2 v2.10.0/go.mod h1:UgQUb2N/pmueQYH9bfqFioWxzYCZXSfF8Jw03O5sjqA= github.com/linode/linodego v1.43.0 h1:sGeBB3caZt7vKBoPS5p4AVzmlG4JoqQOdigIibx3egk= github.com/linode/linodego v1.43.0/go.mod h1:n4TMFu1UVNala+icHqrTEFFaicYSF74cSAUG5zkTwfA= github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= diff --git a/go.work.sum b/go.work.sum index 6af9e9dfb78..6d37067853e 100644 --- a/go.work.sum +++ b/go.work.sum @@ -1,959 +1,242 @@ buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.31.0-20230802163732-1c33ebd9ecfa.1 h1:tdpHgTbmbvEIARu+bixzmleMi14+3imnpoFXz+Qzjp4= buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.31.0-20230802163732-1c33ebd9ecfa.1/go.mod h1:xafc+XIsTxTy76GJQ1TKgvJWsSugFBqMaN27WhUblew= cel.dev/expr v0.18.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= -cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= -cloud.google.com/go v0.110.6/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= -cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= -cloud.google.com/go v0.110.8/go.mod h1:Iz8AkXJf1qmxC3Oxoep8R1T36w8B92yU29PcBhHO5fk= -cloud.google.com/go v0.110.9/go.mod h1:rpxevX/0Lqvlbc88b7Sc1SPNdyK1riNBTUU6JXhYNpM= -cloud.google.com/go v0.110.10/go.mod h1:v1OoFqYxiBkUrruItNM3eT4lLByNjxmJSV/xDKJNnic= -cloud.google.com/go v0.111.0/go.mod h1:0mibmpKP1TyOOFYQY5izo0LnT+ecvOQ0Sg3OdmMiNRU= -cloud.google.com/go v0.112.0/go.mod h1:3jEEVwZ/MHU4djK5t5RHuKOA/GbLddgTdVubX1qnPD4= -cloud.google.com/go/accessapproval v1.7.1/go.mod h1:JYczztsHRMK7NTXb6Xw+dwbs/WnOJxbo/2mTI+Kgg68= -cloud.google.com/go/accessapproval v1.7.2/go.mod h1:/gShiq9/kK/h8T/eEn1BTzalDvk0mZxJlhfw0p+Xuc0= -cloud.google.com/go/accessapproval v1.7.3/go.mod h1:4l8+pwIxGTNqSf4T3ds8nLO94NQf0W/KnMNuQ9PbnP8= -cloud.google.com/go/accessapproval v1.7.4/go.mod h1:/aTEh45LzplQgFYdQdwPMR9YdX0UlhBmvB84uAmQKUc= -cloud.google.com/go/accessapproval v1.7.5/go.mod h1:g88i1ok5dvQ9XJsxpUInWWvUBrIZhyPDPbk4T01OoJ0= cloud.google.com/go/accessapproval v1.8.1 h1:WC6pA5Gyqkrvdc18AHvriShwk8wgMe9EWvBAQSLxTc8= cloud.google.com/go/accessapproval v1.8.1/go.mod h1:3HAtm2ertsWdwgjSGObyas6fj3ZC/3zwV2WVZXO53sU= -cloud.google.com/go/accesscontextmanager v1.8.0/go.mod h1:uI+AI/r1oyWK99NN8cQ3UK76AMelMzgZCvJfsi2c+ps= -cloud.google.com/go/accesscontextmanager v1.8.1/go.mod h1:JFJHfvuaTC+++1iL1coPiG1eu5D24db2wXCDWDjIrxo= -cloud.google.com/go/accesscontextmanager v1.8.2/go.mod h1:E6/SCRM30elQJ2PKtFMs2YhfJpZSNcJyejhuzoId4Zk= -cloud.google.com/go/accesscontextmanager v1.8.3/go.mod h1:4i/JkF2JiFbhLnnpnfoTX5vRXfhf9ukhU1ANOTALTOQ= -cloud.google.com/go/accesscontextmanager v1.8.4/go.mod h1:ParU+WbMpD34s5JFEnGAnPBYAgUHozaTmDJU7aCU9+M= -cloud.google.com/go/accesscontextmanager v1.8.5/go.mod h1:TInEhcZ7V9jptGNqN3EzZ5XMhT6ijWxTGjzyETwmL0Q= cloud.google.com/go/accesscontextmanager v1.9.1 h1:+C7HM05/h80znK+8VNu25wAimueda6/NGNdus+jxaHI= cloud.google.com/go/accesscontextmanager v1.9.1/go.mod h1:wUVSoz8HmG7m9miQTh6smbyYuNOJrvZukK5g6WxSOp0= -cloud.google.com/go/aiplatform v1.45.0/go.mod h1:Iu2Q7sC7QGhXUeOhAj/oCK9a+ULz1O4AotZiqjQ8MYA= -cloud.google.com/go/aiplatform v1.48.0/go.mod h1:Iu2Q7sC7QGhXUeOhAj/oCK9a+ULz1O4AotZiqjQ8MYA= -cloud.google.com/go/aiplatform v1.50.0/go.mod h1:IRc2b8XAMTa9ZmfJV1BCCQbieWWvDnP1A8znyz5N7y4= -cloud.google.com/go/aiplatform v1.51.0/go.mod h1:IRc2b8XAMTa9ZmfJV1BCCQbieWWvDnP1A8znyz5N7y4= -cloud.google.com/go/aiplatform v1.51.1/go.mod h1:kY3nIMAVQOK2XDqDPHaOuD9e+FdMA6OOpfBjsvaFSOo= -cloud.google.com/go/aiplatform v1.51.2/go.mod h1:hCqVYB3mY45w99TmetEoe8eCQEwZEp9WHxeZdcv9phw= -cloud.google.com/go/aiplatform v1.52.0/go.mod h1:pwZMGvqe0JRkI1GWSZCtnAfrR4K1bv65IHILGA//VEU= -cloud.google.com/go/aiplatform v1.54.0/go.mod h1:pwZMGvqe0JRkI1GWSZCtnAfrR4K1bv65IHILGA//VEU= -cloud.google.com/go/aiplatform v1.57.0/go.mod h1:pwZMGvqe0JRkI1GWSZCtnAfrR4K1bv65IHILGA//VEU= -cloud.google.com/go/aiplatform v1.58.0/go.mod h1:pwZMGvqe0JRkI1GWSZCtnAfrR4K1bv65IHILGA//VEU= -cloud.google.com/go/aiplatform v1.58.2/go.mod h1:c3kCiVmb6UC1dHAjZjcpDj6ZS0bHQ2slL88ZjC2LtlA= -cloud.google.com/go/aiplatform v1.60.0/go.mod h1:eTlGuHOahHprZw3Hio5VKmtThIOak5/qy6pzdsqcQnM= cloud.google.com/go/aiplatform v1.68.0 h1:EPPqgHDJpBZKRvv+OsB3cr0jYz3EL2pZ+802rBPcG8U= cloud.google.com/go/aiplatform v1.68.0/go.mod h1:105MFA3svHjC3Oazl7yjXAmIR89LKhRAeNdnDKJczME= -cloud.google.com/go/analytics v0.21.2/go.mod h1:U8dcUtmDmjrmUTnnnRnI4m6zKn/yaA5N9RlEkYFHpQo= -cloud.google.com/go/analytics v0.21.3/go.mod h1:U8dcUtmDmjrmUTnnnRnI4m6zKn/yaA5N9RlEkYFHpQo= -cloud.google.com/go/analytics v0.21.4/go.mod h1:zZgNCxLCy8b2rKKVfC1YkC2vTrpfZmeRCySM3aUbskA= -cloud.google.com/go/analytics v0.21.5/go.mod h1:BQtOBHWTlJ96axpPPnw5CvGJ6i3Ve/qX2fTxR8qWyr8= -cloud.google.com/go/analytics v0.21.6/go.mod h1:eiROFQKosh4hMaNhF85Oc9WO97Cpa7RggD40e/RBy8w= -cloud.google.com/go/analytics v0.22.0/go.mod h1:eiROFQKosh4hMaNhF85Oc9WO97Cpa7RggD40e/RBy8w= -cloud.google.com/go/analytics v0.23.0/go.mod h1:YPd7Bvik3WS95KBok2gPXDqQPHy08TsCQG6CdUCb+u0= cloud.google.com/go/analytics v0.25.1 h1:tMlK9KGTwHYASagAHXXbIPUVCRknA0Yv4jquim5HdRE= cloud.google.com/go/analytics v0.25.1/go.mod h1:hrAWcN/7tqyYwF/f60Nph1yz5UE3/PxOPzzFsJgtU+Y= -cloud.google.com/go/apigateway v1.6.1/go.mod h1:ufAS3wpbRjqfZrzpvLC2oh0MFlpRJm2E/ts25yyqmXA= -cloud.google.com/go/apigateway v1.6.2/go.mod h1:CwMC90nnZElorCW63P2pAYm25AtQrHfuOkbRSHj0bT8= -cloud.google.com/go/apigateway v1.6.3/go.mod h1:k68PXWpEs6BVDTtnLQAyG606Q3mz8pshItwPXjgv44Y= -cloud.google.com/go/apigateway v1.6.4/go.mod h1:0EpJlVGH5HwAN4VF4Iec8TAzGN1aQgbxAWGJsnPCGGY= -cloud.google.com/go/apigateway v1.6.5/go.mod h1:6wCwvYRckRQogyDDltpANi3zsCDl6kWi0b4Je+w2UiI= cloud.google.com/go/apigateway v1.7.1 h1:BeR+5NtpGxsUoK8wa/IPkanORjqZdlyNmXZ8ke3tOhc= cloud.google.com/go/apigateway v1.7.1/go.mod h1:5JBcLrl7GHSGRzuDaISd5u0RKV05DNFiq4dRdfrhCP0= -cloud.google.com/go/apigeeconnect v1.6.1/go.mod h1:C4awq7x0JpLtrlQCr8AzVIzAaYgngRqWf9S5Uhg+wWs= -cloud.google.com/go/apigeeconnect v1.6.2/go.mod h1:s6O0CgXT9RgAxlq3DLXvG8riw8PYYbU/v25jqP3Dy18= -cloud.google.com/go/apigeeconnect v1.6.3/go.mod h1:peG0HFQ0si2bN15M6QSjEW/W7Gy3NYkWGz7pFz13cbo= -cloud.google.com/go/apigeeconnect v1.6.4/go.mod h1:CapQCWZ8TCjnU0d7PobxhpOdVz/OVJ2Hr/Zcuu1xFx0= -cloud.google.com/go/apigeeconnect v1.6.5/go.mod h1:MEKm3AiT7s11PqTfKE3KZluZA9O91FNysvd3E6SJ6Ow= cloud.google.com/go/apigeeconnect v1.7.1 h1:yMWIb/lv69K7Qz6Brv63u6gIACefIPKQSiI2aFXnJxo= cloud.google.com/go/apigeeconnect v1.7.1/go.mod h1:olkn1lOhIA/aorreenFzfEcEXmFN2pyAwkaUFbug9ZY= -cloud.google.com/go/apigeeregistry v0.7.1/go.mod h1:1XgyjZye4Mqtw7T9TsY4NW10U7BojBvG4RMD+vRDrIw= -cloud.google.com/go/apigeeregistry v0.7.2/go.mod h1:9CA2B2+TGsPKtfi3F7/1ncCCsL62NXBRfM6iPoGSM+8= -cloud.google.com/go/apigeeregistry v0.8.1/go.mod h1:MW4ig1N4JZQsXmBSwH4rwpgDonocz7FPBSw6XPGHmYw= -cloud.google.com/go/apigeeregistry v0.8.2/go.mod h1:h4v11TDGdeXJDJvImtgK2AFVvMIgGWjSb0HRnBSjcX8= -cloud.google.com/go/apigeeregistry v0.8.3/go.mod h1:aInOWnqF4yMQx8kTjDqHNXjZGh/mxeNlAf52YqtASUs= cloud.google.com/go/apigeeregistry v0.9.1 h1:AfMllcPbJ+qMgbYK2bC5QDPd8SmE8wQ5msiDILuxVm4= cloud.google.com/go/apigeeregistry v0.9.1/go.mod h1:XCwK9CS65ehi26z7E8/Vl4PEX5c/JJxpfxlB1QEyrZw= cloud.google.com/go/apikeys v0.6.0 h1:B9CdHFZTFjVti89tmyXXrO+7vSNo2jvZuHG8zD5trdQ= -cloud.google.com/go/appengine v1.8.1/go.mod h1:6NJXGLVhZCN9aQ/AEDvmfzKEfoYBlfB80/BHiKVputY= -cloud.google.com/go/appengine v1.8.2/go.mod h1:WMeJV9oZ51pvclqFN2PqHoGnys7rK0rz6s3Mp6yMvDo= -cloud.google.com/go/appengine v1.8.3/go.mod h1:2oUPZ1LVZ5EXi+AF1ihNAF+S8JrzQ3till5m9VQkrsk= -cloud.google.com/go/appengine v1.8.4/go.mod h1:TZ24v+wXBujtkK77CXCpjZbnuTvsFNT41MUaZ28D6vg= -cloud.google.com/go/appengine v1.8.5/go.mod h1:uHBgNoGLTS5di7BvU25NFDuKa82v0qQLjyMJLuPQrVo= cloud.google.com/go/appengine v1.9.1 h1:mQMmn1Dv0DDLsDjYxfS+cVwQa8+ue++ymVeD1jkXze0= cloud.google.com/go/appengine v1.9.1/go.mod h1:jtguveqRWFfjrk3k/7SlJz1FpDBZhu5CWSRu+HBgClk= -cloud.google.com/go/area120 v0.8.1/go.mod h1:BVfZpGpB7KFVNxPiQBuHkX6Ed0rS51xIgmGyjrAfzsg= -cloud.google.com/go/area120 v0.8.2/go.mod h1:a5qfo+x77SRLXnCynFWPUZhnZGeSgvQ+Y0v1kSItkh4= -cloud.google.com/go/area120 v0.8.3/go.mod h1:5zj6pMzVTH+SVHljdSKC35sriR/CVvQZzG/Icdyriw0= -cloud.google.com/go/area120 v0.8.4/go.mod h1:jfawXjxf29wyBXr48+W+GyX/f8fflxp642D/bb9v68M= -cloud.google.com/go/area120 v0.8.5/go.mod h1:BcoFCbDLZjsfe4EkCnEq1LKvHSK0Ew/zk5UFu6GMyA0= cloud.google.com/go/area120 v0.9.1 h1:YfDWbKHRHmhpd8ejTmAeK6eYi3n0qJKvPNEj1ON19PY= cloud.google.com/go/area120 v0.9.1/go.mod h1:foV1BSrnjVL/KydBnAlUQFSy85kWrMwGSmRfIraC+JU= -cloud.google.com/go/artifactregistry v1.14.1/go.mod h1:nxVdG19jTaSTu7yA7+VbWL346r3rIdkZ142BSQqhn5E= -cloud.google.com/go/artifactregistry v1.14.2/go.mod h1:Xk+QbsKEb0ElmyeMfdHAey41B+qBq3q5R5f5xD4XT3U= -cloud.google.com/go/artifactregistry v1.14.3/go.mod h1:A2/E9GXnsyXl7GUvQ/2CjHA+mVRoWAXC0brg2os+kNI= -cloud.google.com/go/artifactregistry v1.14.4/go.mod h1:SJJcZTMv6ce0LDMUnihCN7WSrI+kBSFV0KIKo8S8aYU= -cloud.google.com/go/artifactregistry v1.14.6/go.mod h1:np9LSFotNWHcjnOgh8UVK0RFPCTUGbO0ve3384xyHfE= -cloud.google.com/go/artifactregistry v1.14.7/go.mod h1:0AUKhzWQzfmeTvT4SjfI4zjot72EMfrkvL9g9aRjnnM= cloud.google.com/go/artifactregistry v1.15.1 h1:ANE2nBEqP2vGGA/5plRRUpatT3E/3ydSK8Z+lXiV69s= cloud.google.com/go/artifactregistry v1.15.1/go.mod h1:ExJb4VN+IMTQWO5iY+mjcY19Rz9jUxCVGZ1YuyAgPBw= -cloud.google.com/go/asset v1.14.1/go.mod h1:4bEJ3dnHCqWCDbWJ/6Vn7GVI9LerSi7Rfdi03hd+WTQ= -cloud.google.com/go/asset v1.15.0/go.mod h1:tpKafV6mEut3+vN9ScGvCHXHj7FALFVta+okxFECHcg= -cloud.google.com/go/asset v1.15.1/go.mod h1:yX/amTvFWRpp5rcFq6XbCxzKT8RJUam1UoboE179jU4= -cloud.google.com/go/asset v1.15.2/go.mod h1:B6H5tclkXvXz7PD22qCA2TDxSVQfasa3iDlM89O2NXs= -cloud.google.com/go/asset v1.15.3/go.mod h1:yYLfUD4wL4X589A9tYrv4rFrba0QlDeag0CMcM5ggXU= -cloud.google.com/go/asset v1.16.0/go.mod h1:yYLfUD4wL4X589A9tYrv4rFrba0QlDeag0CMcM5ggXU= -cloud.google.com/go/asset v1.17.0/go.mod h1:yYLfUD4wL4X589A9tYrv4rFrba0QlDeag0CMcM5ggXU= -cloud.google.com/go/asset v1.17.1/go.mod h1:byvDw36UME5AzGNK7o4JnOnINkwOZ1yRrGrKIahHrng= -cloud.google.com/go/asset v1.17.2/go.mod h1:SVbzde67ehddSoKf5uebOD1sYw8Ab/jD/9EIeWg99q4= cloud.google.com/go/asset v1.20.2 h1:wAGSAzAmMC/KEFGZ6Z0zv3jOlz1fjBxuO7SiRX9FMuQ= cloud.google.com/go/asset v1.20.2/go.mod h1:IM1Kpzzo3wq7R/GEiktitzZyXx2zVpWqs9/5EGYs0GY= -cloud.google.com/go/assuredworkloads v1.11.1/go.mod h1:+F04I52Pgn5nmPG36CWFtxmav6+7Q+c5QyJoL18Lry0= -cloud.google.com/go/assuredworkloads v1.11.2/go.mod h1:O1dfr+oZJMlE6mw0Bp0P1KZSlj5SghMBvTpZqIcUAW4= -cloud.google.com/go/assuredworkloads v1.11.3/go.mod h1:vEjfTKYyRUaIeA0bsGJceFV2JKpVRgyG2op3jfa59Zs= -cloud.google.com/go/assuredworkloads v1.11.4/go.mod h1:4pwwGNwy1RP0m+y12ef3Q/8PaiWrIDQ6nD2E8kvWI9U= -cloud.google.com/go/assuredworkloads v1.11.5/go.mod h1:FKJ3g3ZvkL2D7qtqIGnDufFkHxwIpNM9vtmhvt+6wqk= cloud.google.com/go/assuredworkloads v1.12.1 h1:B+hWc62fYL8NdntPjx0rzJJ67qx99w6dCeIVDpHf7QE= cloud.google.com/go/assuredworkloads v1.12.1/go.mod h1:nBnkK2GZNSdtjU3ER75oC5fikub5/+QchbolKgnMI/I= -cloud.google.com/go/auth v0.2.0/go.mod h1:+yb+oy3/P0geX6DLKlqiGHARGR6EX2GRtYCzWOCQSbU= -cloud.google.com/go/auth/oauth2adapt v0.2.0/go.mod h1:AfqujpDAlTfLfeCIl/HJZZlIxD8+nJoZ5e0x1IxGq5k= -cloud.google.com/go/automl v1.13.1/go.mod h1:1aowgAHWYZU27MybSCFiukPO7xnyawv7pt3zK4bheQE= -cloud.google.com/go/automl v1.13.2/go.mod h1:gNY/fUmDEN40sP8amAX3MaXkxcqPIn7F1UIIPZpy4Mg= -cloud.google.com/go/automl v1.13.3/go.mod h1:Y8KwvyAZFOsMAPqUCfNu1AyclbC6ivCUF/MTwORymyY= -cloud.google.com/go/automl v1.13.4/go.mod h1:ULqwX/OLZ4hBVfKQaMtxMSTlPx0GqGbWN8uA/1EqCP8= -cloud.google.com/go/automl v1.13.5/go.mod h1:MDw3vLem3yh+SvmSgeYUmUKqyls6NzSumDm9OJ3xJ1Y= cloud.google.com/go/automl v1.14.1 h1:IrNnM7oClTzfFcf5XgaZCGwicETU2aCmrGzE8U2DlVs= cloud.google.com/go/automl v1.14.1/go.mod h1:BocG5mhT32cjmf5CXxVsdSM04VXzJW7chVT7CpSL2kk= -cloud.google.com/go/baremetalsolution v1.1.1/go.mod h1:D1AV6xwOksJMV4OSlWHtWuFNZZYujJknMAP4Qa27QIA= -cloud.google.com/go/baremetalsolution v1.2.0/go.mod h1:68wi9AwPYkEWIUT4SvSGS9UJwKzNpshjHsH4lzk8iOw= -cloud.google.com/go/baremetalsolution v1.2.1/go.mod h1:3qKpKIw12RPXStwQXcbhfxVj1dqQGEvcmA+SX/mUR88= -cloud.google.com/go/baremetalsolution v1.2.2/go.mod h1:O5V6Uu1vzVelYahKfwEWRMaS3AbCkeYHy3145s1FkhM= -cloud.google.com/go/baremetalsolution v1.2.3/go.mod h1:/UAQ5xG3faDdy180rCUv47e0jvpp3BFxT+Cl0PFjw5g= -cloud.google.com/go/baremetalsolution v1.2.4/go.mod h1:BHCmxgpevw9IEryE99HbYEfxXkAEA3hkMJbYYsHtIuY= cloud.google.com/go/baremetalsolution v1.3.1 h1:Zbsrhw8vm4Byki+ynVuACZ6jxYiKzi1f8Hac5zXGD8Y= cloud.google.com/go/baremetalsolution v1.3.1/go.mod h1:D1djGGmBl4M6VlyjOMc1SEzDYlO4EeEG1TCUv5mCPi0= -cloud.google.com/go/batch v1.3.1/go.mod h1:VguXeQKXIYaeeIYbuozUmBR13AfL4SJP7IltNPS+A4A= -cloud.google.com/go/batch v1.4.1/go.mod h1:KdBmDD61K0ovcxoRHGrN6GmOBWeAOyCgKD0Mugx4Fkk= -cloud.google.com/go/batch v1.5.0/go.mod h1:KdBmDD61K0ovcxoRHGrN6GmOBWeAOyCgKD0Mugx4Fkk= -cloud.google.com/go/batch v1.5.1/go.mod h1:RpBuIYLkQu8+CWDk3dFD/t/jOCGuUpkpX+Y0n1Xccs8= -cloud.google.com/go/batch v1.6.1/go.mod h1:urdpD13zPe6YOK+6iZs/8/x2VBRofvblLpx0t57vM98= -cloud.google.com/go/batch v1.6.3/go.mod h1:J64gD4vsNSA2O5TtDB5AAux3nJ9iV8U3ilg3JDBYejU= -cloud.google.com/go/batch v1.7.0/go.mod h1:J64gD4vsNSA2O5TtDB5AAux3nJ9iV8U3ilg3JDBYejU= -cloud.google.com/go/batch v1.8.0/go.mod h1:k8V7f6VE2Suc0zUM4WtoibNrA6D3dqBpB+++e3vSGYc= cloud.google.com/go/batch v1.11.1 h1:50TRhaaZv7QDCb60KcZUPkGx1oO46srDp5076wZkgI8= cloud.google.com/go/batch v1.11.1/go.mod h1:4GbJXfdxU8GH6uuo8G47y5tEFOgTLCL9pMKCUcn7VxE= -cloud.google.com/go/beyondcorp v0.6.1/go.mod h1:YhxDWw946SCbmcWo3fAhw3V4XZMSpQ/VYfcKGAEU8/4= -cloud.google.com/go/beyondcorp v1.0.0/go.mod h1:YhxDWw946SCbmcWo3fAhw3V4XZMSpQ/VYfcKGAEU8/4= -cloud.google.com/go/beyondcorp v1.0.1/go.mod h1:zl/rWWAFVeV+kx+X2Javly7o1EIQThU4WlkynffL/lk= -cloud.google.com/go/beyondcorp v1.0.2/go.mod h1:m8cpG7caD+5su+1eZr+TSvF6r21NdLJk4f9u4SP2Ntc= -cloud.google.com/go/beyondcorp v1.0.3/go.mod h1:HcBvnEd7eYr+HGDd5ZbuVmBYX019C6CEXBonXbCVwJo= -cloud.google.com/go/beyondcorp v1.0.4/go.mod h1:Gx8/Rk2MxrvWfn4WIhHIG1NV7IBfg14pTKv1+EArVcc= cloud.google.com/go/beyondcorp v1.1.1 h1:owviaab14M9ySEvCj3EZdfzkRLnE+5j4JIkqVaQtEUU= cloud.google.com/go/beyondcorp v1.1.1/go.mod h1:L09o0gLkgXMxCZs4qojrgpI2/dhWtasMc71zPPiHMn4= -cloud.google.com/go/bigquery v1.52.0/go.mod h1:3b/iXjRQGU4nKa87cXeg6/gogLjO8C6PmuM8i5Bi/u4= -cloud.google.com/go/bigquery v1.53.0/go.mod h1:3b/iXjRQGU4nKa87cXeg6/gogLjO8C6PmuM8i5Bi/u4= -cloud.google.com/go/bigquery v1.55.0/go.mod h1:9Y5I3PN9kQWuid6183JFhOGOW3GcirA5LpsKCUn+2ec= -cloud.google.com/go/bigquery v1.56.0/go.mod h1:KDcsploXTEY7XT3fDQzMUZlpQLHzE4itubHrnmhUrZA= -cloud.google.com/go/bigquery v1.57.1/go.mod h1:iYzC0tGVWt1jqSzBHqCr3lrRn0u13E8e+AqowBsDgug= -cloud.google.com/go/bigquery v1.58.0/go.mod h1:0eh4mWNY0KrBTjUzLjoYImapGORq9gEPT7MWjCy9lik= -cloud.google.com/go/bigquery v1.59.1/go.mod h1:VP1UJYgevyTwsV7desjzNzDND5p6hZB+Z8gZJN1GQUc= cloud.google.com/go/bigquery v1.63.1 h1:/6syiWrSpardKNxdvldS5CUTRJX1iIkSPXCjLjiGL+g= cloud.google.com/go/bigquery v1.63.1/go.mod h1:ufaITfroCk17WTqBhMpi8CRjsfHjMX07pDrQaRKKX2o= cloud.google.com/go/bigtable v1.33.0 h1:2BDaWLRAwXO14DJL/u8crbV2oUbMZkIa2eGq8Yao1bk= cloud.google.com/go/bigtable v1.33.0/go.mod h1:HtpnH4g25VT1pejHRtInlFPnN5sjTxbQlsYBjh9t5l0= -cloud.google.com/go/billing v1.16.0/go.mod h1:y8vx09JSSJG02k5QxbycNRrN7FGZB6F3CAcgum7jvGA= -cloud.google.com/go/billing v1.17.0/go.mod h1:Z9+vZXEq+HwH7bhJkyI4OQcR6TSbeMrjlpEjO2vzY64= -cloud.google.com/go/billing v1.17.1/go.mod h1:Z9+vZXEq+HwH7bhJkyI4OQcR6TSbeMrjlpEjO2vzY64= -cloud.google.com/go/billing v1.17.2/go.mod h1:u/AdV/3wr3xoRBk5xvUzYMS1IawOAPwQMuHgHMdljDg= -cloud.google.com/go/billing v1.17.3/go.mod h1:z83AkoZ7mZwBGT3yTnt6rSGI1OOsHSIi6a5M3mJ8NaU= -cloud.google.com/go/billing v1.17.4/go.mod h1:5DOYQStCxquGprqfuid/7haD7th74kyMBHkjO/OvDtk= -cloud.google.com/go/billing v1.18.0/go.mod h1:5DOYQStCxquGprqfuid/7haD7th74kyMBHkjO/OvDtk= -cloud.google.com/go/billing v1.18.2/go.mod h1:PPIwVsOOQ7xzbADCwNe8nvK776QpfrOAUkvKjCUcpSE= cloud.google.com/go/billing v1.19.1 h1:BtbMCM9QDWiszfNXEAcq0MB6vgCuc0/yzP3vye2Kz3U= cloud.google.com/go/billing v1.19.1/go.mod h1:c5l7ORJjOLH/aASJqUqNsEmwrhfjWZYHX+z0fIhuVpo= -cloud.google.com/go/binaryauthorization v1.6.1/go.mod h1:TKt4pa8xhowwffiBmbrbcxijJRZED4zrqnwZ1lKH51U= -cloud.google.com/go/binaryauthorization v1.7.0/go.mod h1:Zn+S6QqTMn6odcMU1zDZCJxPjU2tZPV1oDl45lWY154= -cloud.google.com/go/binaryauthorization v1.7.1/go.mod h1:GTAyfRWYgcbsP3NJogpV3yeunbUIjx2T9xVeYovtURE= -cloud.google.com/go/binaryauthorization v1.7.2/go.mod h1:kFK5fQtxEp97m92ziy+hbu+uKocka1qRRL8MVJIgjv0= -cloud.google.com/go/binaryauthorization v1.7.3/go.mod h1:VQ/nUGRKhrStlGr+8GMS8f6/vznYLkdK5vaKfdCIpvU= -cloud.google.com/go/binaryauthorization v1.8.0/go.mod h1:VQ/nUGRKhrStlGr+8GMS8f6/vznYLkdK5vaKfdCIpvU= -cloud.google.com/go/binaryauthorization v1.8.1/go.mod h1:1HVRyBerREA/nhI7yLang4Zn7vfNVA3okoAR9qYQJAQ= cloud.google.com/go/binaryauthorization v1.9.1 h1:fVtOG5rVU0eaVh2G2ORdT7nigsnK1R1JpqfGzW861OM= cloud.google.com/go/binaryauthorization v1.9.1/go.mod h1:jqBzP68bfzjoiMFT6Q1EdZtKJG39zW9ywwzHuv7V8ms= -cloud.google.com/go/certificatemanager v1.7.1/go.mod h1:iW8J3nG6SaRYImIa+wXQ0g8IgoofDFRp5UMzaNk1UqI= -cloud.google.com/go/certificatemanager v1.7.2/go.mod h1:15SYTDQMd00kdoW0+XY5d9e+JbOPjp24AvF48D8BbcQ= -cloud.google.com/go/certificatemanager v1.7.3/go.mod h1:T/sZYuC30PTag0TLo28VedIRIj1KPGcOQzjWAptHa00= -cloud.google.com/go/certificatemanager v1.7.4/go.mod h1:FHAylPe/6IIKuaRmHbjbdLhGhVQ+CWHSD5Jq0k4+cCE= -cloud.google.com/go/certificatemanager v1.7.5/go.mod h1:uX+v7kWqy0Y3NG/ZhNvffh0kuqkKZIXdvlZRO7z0VtM= cloud.google.com/go/certificatemanager v1.9.1 h1:fULhIdwsz3SoZfiXw8XaxSJBpRTR0xwsJleO+wEbbKA= cloud.google.com/go/certificatemanager v1.9.1/go.mod h1:a6bXZULtd6iQTRuSVs1fopcHLMJ/T3zSpIB7aJaq/js= -cloud.google.com/go/channel v1.16.0/go.mod h1:eN/q1PFSl5gyu0dYdmxNXscY/4Fi7ABmeHCJNf/oHmc= -cloud.google.com/go/channel v1.17.0/go.mod h1:RpbhJsGi/lXWAUM1eF4IbQGbsfVlg2o8Iiy2/YLfVT0= -cloud.google.com/go/channel v1.17.1/go.mod h1:xqfzcOZAcP4b/hUDH0GkGg1Sd5to6di1HOJn/pi5uBQ= -cloud.google.com/go/channel v1.17.2/go.mod h1:aT2LhnftnyfQceFql5I/mP8mIbiiJS4lWqgXA815zMk= -cloud.google.com/go/channel v1.17.3/go.mod h1:QcEBuZLGGrUMm7kNj9IbU1ZfmJq2apotsV83hbxX7eE= -cloud.google.com/go/channel v1.17.4/go.mod h1:QcEBuZLGGrUMm7kNj9IbU1ZfmJq2apotsV83hbxX7eE= -cloud.google.com/go/channel v1.17.5/go.mod h1:FlpaOSINDAXgEext0KMaBq/vwpLMkkPAw9b2mApQeHc= cloud.google.com/go/channel v1.19.0 h1:YdCa/Y6lhGVeR058gQGhTunEuR9zVuheukKL+pcldgI= cloud.google.com/go/channel v1.19.0/go.mod h1:8BEvuN5hWL4tT0rmJR4N8xsZHdfGof+KwemjQH6oXsw= -cloud.google.com/go/cloudbuild v1.10.1/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= -cloud.google.com/go/cloudbuild v1.13.0/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= -cloud.google.com/go/cloudbuild v1.14.0/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= -cloud.google.com/go/cloudbuild v1.14.1/go.mod h1:K7wGc/3zfvmYWOWwYTgF/d/UVJhS4pu+HAy7PL7mCsU= -cloud.google.com/go/cloudbuild v1.14.2/go.mod h1:Bn6RO0mBYk8Vlrt+8NLrru7WXlQ9/RDWz2uo5KG1/sg= -cloud.google.com/go/cloudbuild v1.14.3/go.mod h1:eIXYWmRt3UtggLnFGx4JvXcMj4kShhVzGndL1LwleEM= -cloud.google.com/go/cloudbuild v1.15.0/go.mod h1:eIXYWmRt3UtggLnFGx4JvXcMj4kShhVzGndL1LwleEM= -cloud.google.com/go/cloudbuild v1.15.1/go.mod h1:gIofXZSu+XD2Uy+qkOrGKEx45zd7s28u/k8f99qKals= cloud.google.com/go/cloudbuild v1.18.0 h1:82f6g0AzacK1bbO0E5ZqixWc4nRzWu4ichIQ0QKNtAQ= cloud.google.com/go/cloudbuild v1.18.0/go.mod h1:KCHWGIoS/5fj+By9YmgIQnUiDq8P6YURWOjX3hoc6As= -cloud.google.com/go/clouddms v1.6.1/go.mod h1:Ygo1vL52Ov4TBZQquhz5fiw2CQ58gvu+PlS6PVXCpZI= -cloud.google.com/go/clouddms v1.7.0/go.mod h1:MW1dC6SOtI/tPNCciTsXtsGNEM0i0OccykPvv3hiYeM= -cloud.google.com/go/clouddms v1.7.1/go.mod h1:o4SR8U95+P7gZ/TX+YbJxehOCsM+fe6/brlrFquiszk= -cloud.google.com/go/clouddms v1.7.2/go.mod h1:Rk32TmWmHo64XqDvW7jgkFQet1tUKNVzs7oajtJT3jU= -cloud.google.com/go/clouddms v1.7.3/go.mod h1:fkN2HQQNUYInAU3NQ3vRLkV2iWs8lIdmBKOx4nrL6Hc= -cloud.google.com/go/clouddms v1.7.4/go.mod h1:RdrVqoFG9RWI5AvZ81SxJ/xvxPdtcRhFotwdE79DieY= cloud.google.com/go/clouddms v1.8.1 h1:vf5R4/FoLHxEP2BBKEafLHfYFWa6Zd9gwrXe/FjrwUg= cloud.google.com/go/clouddms v1.8.1/go.mod h1:bmW2eDFH1LjuwkHcKKeeppcmuBGS0r6Qz6TXanehKP0= -cloud.google.com/go/cloudtasks v1.11.1/go.mod h1:a9udmnou9KO2iulGscKR0qBYjreuX8oHwpmFsKspEvM= -cloud.google.com/go/cloudtasks v1.12.1/go.mod h1:a9udmnou9KO2iulGscKR0qBYjreuX8oHwpmFsKspEvM= -cloud.google.com/go/cloudtasks v1.12.2/go.mod h1:A7nYkjNlW2gUoROg1kvJrQGhJP/38UaWwsnuBDOBVUk= -cloud.google.com/go/cloudtasks v1.12.3/go.mod h1:GPVXhIOSGEaR+3xT4Fp72ScI+HjHffSS4B8+BaBB5Ys= -cloud.google.com/go/cloudtasks v1.12.4/go.mod h1:BEPu0Gtt2dU6FxZHNqqNdGqIG86qyWKBPGnsb7udGY0= -cloud.google.com/go/cloudtasks v1.12.6/go.mod h1:b7c7fe4+TJsFZfDyzO51F7cjq7HLUlRi/KZQLQjDsaY= cloud.google.com/go/cloudtasks v1.13.1 h1:s1JTLBD+WbzQwxYPAwa2WIxPT3kOiv7MSKyvSEgNQtg= cloud.google.com/go/cloudtasks v1.13.1/go.mod h1:dyRD7tEEkLMbHLagb7UugkDa77UVJp9d/6O9lm3ModI= -cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= -cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= -cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= -cloud.google.com/go/compute v1.23.1/go.mod h1:CqB3xpmPKKt3OJpW2ndFIXnA9A4xAy/F3Xp1ixncW78= -cloud.google.com/go/compute v1.23.2/go.mod h1:JJ0atRC0J/oWYiiVBmsSsrRnh92DhZPG4hFDcR04Rns= -cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= -cloud.google.com/go/compute v1.23.4/go.mod h1:/EJMj55asU6kAFnuZET8zqgwgJ9FvXWXOkkfQZa4ioI= -cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40= cloud.google.com/go/compute v1.28.1 h1:XwPcZjgMCnU2tkwY10VleUjSAfpTj9RDn+kGrbYsi8o= cloud.google.com/go/compute v1.28.1/go.mod h1:b72iXMY4FucVry3NR3Li4kVyyTvbMDE7x5WsqvxjsYk= cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= -cloud.google.com/go/contactcenterinsights v1.9.1/go.mod h1:bsg/R7zGLYMVxFFzfh9ooLTruLRCG9fnzhH9KznHhbM= -cloud.google.com/go/contactcenterinsights v1.10.0/go.mod h1:bsg/R7zGLYMVxFFzfh9ooLTruLRCG9fnzhH9KznHhbM= -cloud.google.com/go/contactcenterinsights v1.11.0/go.mod h1:hutBdImE4XNZ1NV4vbPJKSFOnQruhC5Lj9bZqWMTKiU= -cloud.google.com/go/contactcenterinsights v1.11.1/go.mod h1:FeNP3Kg8iteKM80lMwSk3zZZKVxr+PGnAId6soKuXwE= -cloud.google.com/go/contactcenterinsights v1.11.2/go.mod h1:A9PIR5ov5cRcd28KlDbmmXE8Aay+Gccer2h4wzkYFso= -cloud.google.com/go/contactcenterinsights v1.11.3/go.mod h1:HHX5wrz5LHVAwfI2smIotQG9x8Qd6gYilaHcLLLmNis= -cloud.google.com/go/contactcenterinsights v1.12.0/go.mod h1:HHX5wrz5LHVAwfI2smIotQG9x8Qd6gYilaHcLLLmNis= -cloud.google.com/go/contactcenterinsights v1.12.1/go.mod h1:HHX5wrz5LHVAwfI2smIotQG9x8Qd6gYilaHcLLLmNis= -cloud.google.com/go/contactcenterinsights v1.13.0/go.mod h1:ieq5d5EtHsu8vhe2y3amtZ+BE+AQwX5qAy7cpo0POsI= cloud.google.com/go/contactcenterinsights v1.15.0 h1:jHwyL2TQTaLauRRz5Uv7/sL7PNAK1VAMy/UIT9vsFzk= cloud.google.com/go/contactcenterinsights v1.15.0/go.mod h1:6bJGBQrJsnATv2s6Dh/c6HCRanq2kCZ0kIIjRV1G0mI= -cloud.google.com/go/container v1.22.1/go.mod h1:lTNExE2R7f+DLbAN+rJiKTisauFCaoDq6NURZ83eVH4= -cloud.google.com/go/container v1.24.0/go.mod h1:lTNExE2R7f+DLbAN+rJiKTisauFCaoDq6NURZ83eVH4= -cloud.google.com/go/container v1.26.0/go.mod h1:YJCmRet6+6jnYYRS000T6k0D0xUXQgBSaJ7VwI8FBj4= -cloud.google.com/go/container v1.26.1/go.mod h1:5smONjPRUxeEpDG7bMKWfDL4sauswqEtnBK1/KKpR04= -cloud.google.com/go/container v1.26.2/go.mod h1:YlO84xCt5xupVbLaMY4s3XNE79MUJ+49VmkInr6HvF4= -cloud.google.com/go/container v1.27.1/go.mod h1:b1A1gJeTBXVLQ6GGw9/9M4FG94BEGsqJ5+t4d/3N7O4= -cloud.google.com/go/container v1.28.0/go.mod h1:b1A1gJeTBXVLQ6GGw9/9M4FG94BEGsqJ5+t4d/3N7O4= -cloud.google.com/go/container v1.29.0/go.mod h1:b1A1gJeTBXVLQ6GGw9/9M4FG94BEGsqJ5+t4d/3N7O4= -cloud.google.com/go/container v1.30.1/go.mod h1:vkbfX0EnAKL/vgVECs5BZn24e1cJROzgszJirRKQ4Bg= -cloud.google.com/go/container v1.31.0/go.mod h1:7yABn5s3Iv3lmw7oMmyGbeV6tQj86njcTijkkGuvdZA= cloud.google.com/go/container v1.40.0 h1:JVoEg/4RvoGW37r2Eja/cTBc3X9c2loGWYq7QDsRDuI= cloud.google.com/go/container v1.40.0/go.mod h1:wNI1mOUivm+ZkpHMbouutgbD4sQxyphMwK31X5cThY4= -cloud.google.com/go/containeranalysis v0.10.1/go.mod h1:Ya2jiILITMY68ZLPaogjmOMNkwsDrWBSTyBubGXO7j0= -cloud.google.com/go/containeranalysis v0.11.0/go.mod h1:4n2e99ZwpGxpNcz+YsFT1dfOHPQFGcAC8FN2M2/ne/U= -cloud.google.com/go/containeranalysis v0.11.1/go.mod h1:rYlUOM7nem1OJMKwE1SadufX0JP3wnXj844EtZAwWLY= -cloud.google.com/go/containeranalysis v0.11.2/go.mod h1:xibioGBC1MD2j4reTyV1xY1/MvKaz+fyM9ENWhmIeP8= -cloud.google.com/go/containeranalysis v0.11.3/go.mod h1:kMeST7yWFQMGjiG9K7Eov+fPNQcGhb8mXj/UcTiWw9U= -cloud.google.com/go/containeranalysis v0.11.4/go.mod h1:cVZT7rXYBS9NG1rhQbWL9pWbXCKHWJPYraE8/FTSYPE= cloud.google.com/go/containeranalysis v0.13.1 h1:opZRo0HEVLm4ylTbbXw/H68M3vQjdkYOSMfUY63+D+0= cloud.google.com/go/containeranalysis v0.13.1/go.mod h1:bmd9H880BNR4Hc8JspEg8ge9WccSQfO+/N+CYvU3sEA= -cloud.google.com/go/datacatalog v1.14.0/go.mod h1:h0PrGtlihoutNMp/uvwhawLQ9+c63Kz65UFqh49Yo+E= -cloud.google.com/go/datacatalog v1.14.1/go.mod h1:d2CevwTG4yedZilwe+v3E3ZBDRMobQfSG/a6cCCN5R4= -cloud.google.com/go/datacatalog v1.16.0/go.mod h1:d2CevwTG4yedZilwe+v3E3ZBDRMobQfSG/a6cCCN5R4= -cloud.google.com/go/datacatalog v1.17.1/go.mod h1:nCSYFHgtxh2MiEktWIz71s/X+7ds/UT9kp0PC7waCzE= -cloud.google.com/go/datacatalog v1.18.0/go.mod h1:nCSYFHgtxh2MiEktWIz71s/X+7ds/UT9kp0PC7waCzE= -cloud.google.com/go/datacatalog v1.18.1/go.mod h1:TzAWaz+ON1tkNr4MOcak8EBHX7wIRX/gZKM+yTVsv+A= -cloud.google.com/go/datacatalog v1.18.2/go.mod h1:SPVgWW2WEMuWHA+fHodYjmxPiMqcOiWfhc9OD5msigk= -cloud.google.com/go/datacatalog v1.18.3/go.mod h1:5FR6ZIF8RZrtml0VUao22FxhdjkoG+a0866rEnObryM= -cloud.google.com/go/datacatalog v1.19.0/go.mod h1:5FR6ZIF8RZrtml0VUao22FxhdjkoG+a0866rEnObryM= -cloud.google.com/go/datacatalog v1.19.2/go.mod h1:2YbODwmhpLM4lOFe3PuEhHK9EyTzQJ5AXgIy7EDKTEE= -cloud.google.com/go/datacatalog v1.19.3/go.mod h1:ra8V3UAsciBpJKQ+z9Whkxzxv7jmQg1hfODr3N3YPJ4= cloud.google.com/go/datacatalog v1.22.1 h1:i0DyKb/o7j+0vgaFtimcRFjYsD6wFw1jpnODYUyiYRs= cloud.google.com/go/datacatalog v1.22.1/go.mod h1:MscnJl9B2lpYlFoxRjicw19kFTwEke8ReKL5Y/6TWg8= -cloud.google.com/go/dataflow v0.9.1/go.mod h1:Wp7s32QjYuQDWqJPFFlnBKhkAtiFpMTdg00qGbnIHVw= -cloud.google.com/go/dataflow v0.9.2/go.mod h1:vBfdBZ/ejlTaYIGB3zB4T08UshH70vbtZeMD+urnUSo= -cloud.google.com/go/dataflow v0.9.3/go.mod h1:HI4kMVjcHGTs3jTHW/kv3501YW+eloiJSLxkJa/vqFE= -cloud.google.com/go/dataflow v0.9.4/go.mod h1:4G8vAkHYCSzU8b/kmsoR2lWyHJD85oMJPHMtan40K8w= -cloud.google.com/go/dataflow v0.9.5/go.mod h1:udl6oi8pfUHnL0z6UN9Lf9chGqzDMVqcYTcZ1aPnCZQ= cloud.google.com/go/dataflow v0.10.1 h1:RoVpCZ1BjJBH/5mzaXCgNg+l9FgTIYQ7C9xBRGvhkzo= cloud.google.com/go/dataflow v0.10.1/go.mod h1:zP4/tNjONFRcS4NcI9R94YDQEkPalimdbPkijVNJt/g= -cloud.google.com/go/dataform v0.8.1/go.mod h1:3BhPSiw8xmppbgzeBbmDvmSWlwouuJkXsXsb8UBih9M= -cloud.google.com/go/dataform v0.8.2/go.mod h1:X9RIqDs6NbGPLR80tnYoPNiO1w0wenKTb8PxxlhTMKM= -cloud.google.com/go/dataform v0.8.3/go.mod h1:8nI/tvv5Fso0drO3pEjtowz58lodx8MVkdV2q0aPlqg= -cloud.google.com/go/dataform v0.9.1/go.mod h1:pWTg+zGQ7i16pyn0bS1ruqIE91SdL2FDMvEYu/8oQxs= -cloud.google.com/go/dataform v0.9.2/go.mod h1:S8cQUwPNWXo7m/g3DhWHsLBoufRNn9EgFrMgne2j7cI= cloud.google.com/go/dataform v0.10.1 h1:FkOPrxf8sN9J2TMc4CIBhVivhMiO8D0eYN33s5A5Uo4= cloud.google.com/go/dataform v0.10.1/go.mod h1:c5y0hIOBCfszmBcLJyxnELF30gC1qC/NeHdmkzA7TNQ= -cloud.google.com/go/datafusion v1.7.1/go.mod h1:KpoTBbFmoToDExJUso/fcCiguGDk7MEzOWXUsJo0wsI= -cloud.google.com/go/datafusion v1.7.2/go.mod h1:62K2NEC6DRlpNmI43WHMWf9Vg/YvN6QVi8EVwifElI0= -cloud.google.com/go/datafusion v1.7.3/go.mod h1:eoLt1uFXKGBq48jy9LZ+Is8EAVLnmn50lNncLzwYokE= -cloud.google.com/go/datafusion v1.7.4/go.mod h1:BBs78WTOLYkT4GVZIXQCZT3GFpkpDN4aBY4NDX/jVlM= -cloud.google.com/go/datafusion v1.7.5/go.mod h1:bYH53Oa5UiqahfbNK9YuYKteeD4RbQSNMx7JF7peGHc= cloud.google.com/go/datafusion v1.8.1 h1:QqiQs3mSXl4gfeHGOTbK0v1y+tUOnxWJgXm6YWvoqY0= cloud.google.com/go/datafusion v1.8.1/go.mod h1:I5+nRt6Lob4g1eCbcxP4ayRNx8hyOZ8kA3PB/vGd9Lo= -cloud.google.com/go/datalabeling v0.8.1/go.mod h1:XS62LBSVPbYR54GfYQsPXZjTW8UxCK2fkDciSrpRFdY= -cloud.google.com/go/datalabeling v0.8.2/go.mod h1:cyDvGHuJWu9U/cLDA7d8sb9a0tWLEletStu2sTmg3BE= -cloud.google.com/go/datalabeling v0.8.3/go.mod h1:tvPhpGyS/V7lqjmb3V0TaDdGvhzgR1JoW7G2bpi2UTI= -cloud.google.com/go/datalabeling v0.8.4/go.mod h1:Z1z3E6LHtffBGrNUkKwbwbDxTiXEApLzIgmymj8A3S8= -cloud.google.com/go/datalabeling v0.8.5/go.mod h1:IABB2lxQnkdUbMnQaOl2prCOfms20mcPxDBm36lps+s= cloud.google.com/go/datalabeling v0.9.1 h1:FrnZKagECxQy1bL+GQ1bjgwK9+szi1l7gqw7zp+Raqs= cloud.google.com/go/datalabeling v0.9.1/go.mod h1:umplHuZX+x5DItNPV5BFBXau5TDsljLNzEj5AB5uRUM= -cloud.google.com/go/dataplex v1.8.1/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= -cloud.google.com/go/dataplex v1.9.0/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= -cloud.google.com/go/dataplex v1.9.1/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= -cloud.google.com/go/dataplex v1.10.1/go.mod h1:1MzmBv8FvjYfc7vDdxhnLFNskikkB+3vl475/XdCDhs= -cloud.google.com/go/dataplex v1.10.2/go.mod h1:xdC8URdTrCrZMW6keY779ZT1cTOfV8KEPNsw+LTRT1Y= -cloud.google.com/go/dataplex v1.11.1/go.mod h1:mHJYQQ2VEJHsyoC0OdNyy988DvEbPhqFs5OOLffLX0c= -cloud.google.com/go/dataplex v1.11.2/go.mod h1:mHJYQQ2VEJHsyoC0OdNyy988DvEbPhqFs5OOLffLX0c= -cloud.google.com/go/dataplex v1.13.0/go.mod h1:mHJYQQ2VEJHsyoC0OdNyy988DvEbPhqFs5OOLffLX0c= -cloud.google.com/go/dataplex v1.14.0/go.mod h1:mHJYQQ2VEJHsyoC0OdNyy988DvEbPhqFs5OOLffLX0c= -cloud.google.com/go/dataplex v1.14.1/go.mod h1:bWxQAbg6Smg+sca2+Ex7s8D9a5qU6xfXtwmq4BVReps= -cloud.google.com/go/dataplex v1.14.2/go.mod h1:0oGOSFlEKef1cQeAHXy4GZPB/Ife0fz/PxBf+ZymA2U= cloud.google.com/go/dataplex v1.19.1 h1:0pgI0DwijXZq8vyLuGnQXSi9JB6eUaVqzpzhN2veUeE= cloud.google.com/go/dataplex v1.19.1/go.mod h1:WzoQ+vcxrAyM0cjJWmluEDVsg7W88IXXCfuy01BslKE= cloud.google.com/go/dataproc v1.12.0 h1:W47qHL3W4BPkAIbk4SWmIERwsWBaNnWm0P2sdx3YgGU= -cloud.google.com/go/dataproc/v2 v2.0.1/go.mod h1:7Ez3KRHdFGcfY7GcevBbvozX+zyWGcwLJvvAMwCaoZ4= -cloud.google.com/go/dataproc/v2 v2.2.0/go.mod h1:lZR7AQtwZPvmINx5J87DSOOpTfof9LVZju6/Qo4lmcY= -cloud.google.com/go/dataproc/v2 v2.2.1/go.mod h1:QdAJLaBjh+l4PVlVZcmrmhGccosY/omC1qwfQ61Zv/o= -cloud.google.com/go/dataproc/v2 v2.2.2/go.mod h1:aocQywVmQVF4i8CL740rNI/ZRpsaaC1Wh2++BJ7HEJ4= -cloud.google.com/go/dataproc/v2 v2.2.3/go.mod h1:G5R6GBc9r36SXv/RtZIVfB8SipI+xVn0bX5SxUzVYbY= -cloud.google.com/go/dataproc/v2 v2.3.0/go.mod h1:G5R6GBc9r36SXv/RtZIVfB8SipI+xVn0bX5SxUzVYbY= -cloud.google.com/go/dataproc/v2 v2.4.0/go.mod h1:3B1Ht2aRB8VZIteGxQS/iNSJGzt9+CA0WGnDVMEm7Z4= cloud.google.com/go/dataproc/v2 v2.9.0 h1:9fSMjWgFKQfmfKu7V10C5foxU/2iDa8bVkiBB8uh1EU= cloud.google.com/go/dataproc/v2 v2.9.0/go.mod h1:i4365hSwNP6Bx0SAUnzCC6VloeNxChDjJWH6BfVPcbs= -cloud.google.com/go/dataqna v0.8.1/go.mod h1:zxZM0Bl6liMePWsHA8RMGAfmTG34vJMapbHAxQ5+WA8= -cloud.google.com/go/dataqna v0.8.2/go.mod h1:KNEqgx8TTmUipnQsScOoDpq/VlXVptUqVMZnt30WAPs= -cloud.google.com/go/dataqna v0.8.3/go.mod h1:wXNBW2uvc9e7Gl5k8adyAMnLush1KVV6lZUhB+rqNu4= -cloud.google.com/go/dataqna v0.8.4/go.mod h1:mySRKjKg5Lz784P6sCov3p1QD+RZQONRMRjzGNcFd0c= -cloud.google.com/go/dataqna v0.8.5/go.mod h1:vgihg1mz6n7pb5q2YJF7KlXve6tCglInd6XO0JGOlWM= cloud.google.com/go/dataqna v0.9.1 h1:ptKKT+CNwp9Q+9Zxr+npUO7qUwKfyq/oF7/nS7CC6sc= cloud.google.com/go/dataqna v0.9.1/go.mod h1:86DNLE33yEfNDp5F2nrITsmTYubMbsF7zQRzC3CcZrY= -cloud.google.com/go/datastore v1.12.0/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= -cloud.google.com/go/datastore v1.12.1/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= -cloud.google.com/go/datastore v1.13.0/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= -cloud.google.com/go/datastore v1.14.0/go.mod h1:GAeStMBIt9bPS7jMJA85kgkpsMkvseWWXiaHya9Jes8= -cloud.google.com/go/datastore v1.15.0/go.mod h1:GAeStMBIt9bPS7jMJA85kgkpsMkvseWWXiaHya9Jes8= cloud.google.com/go/datastore v1.19.0 h1:p5H3bUQltOa26GcMRAxPoNwoqGkq5v8ftx9/ZBB35MI= cloud.google.com/go/datastore v1.19.0/go.mod h1:KGzkszuj87VT8tJe67GuB+qLolfsOt6bZq/KFuWaahc= -cloud.google.com/go/datastream v1.9.1/go.mod h1:hqnmr8kdUBmrnk65k5wNRoHSCYksvpdZIcZIEl8h43Q= -cloud.google.com/go/datastream v1.10.0/go.mod h1:hqnmr8kdUBmrnk65k5wNRoHSCYksvpdZIcZIEl8h43Q= -cloud.google.com/go/datastream v1.10.1/go.mod h1:7ngSYwnw95YFyTd5tOGBxHlOZiL+OtpjheqU7t2/s/c= -cloud.google.com/go/datastream v1.10.2/go.mod h1:W42TFgKAs/om6x/CdXX5E4oiAsKlH+e8MTGy81zdYt0= -cloud.google.com/go/datastream v1.10.3/go.mod h1:YR0USzgjhqA/Id0Ycu1VvZe8hEWwrkjuXrGbzeDOSEA= -cloud.google.com/go/datastream v1.10.4/go.mod h1:7kRxPdxZxhPg3MFeCSulmAJnil8NJGGvSNdn4p1sRZo= cloud.google.com/go/datastream v1.11.1 h1:YKY2qGKoxPpAvsDMtmJlIwL59SzhEm1DHM2uM4ib0TY= cloud.google.com/go/datastream v1.11.1/go.mod h1:a4j5tnptIxdZ132XboR6uQM/ZHcuv/hLqA6hH3NJWgk= -cloud.google.com/go/deploy v1.11.0/go.mod h1:tKuSUV5pXbn67KiubiUNUejqLs4f5cxxiCNCeyl0F2g= -cloud.google.com/go/deploy v1.13.0/go.mod h1:tKuSUV5pXbn67KiubiUNUejqLs4f5cxxiCNCeyl0F2g= -cloud.google.com/go/deploy v1.13.1/go.mod h1:8jeadyLkH9qu9xgO3hVWw8jVr29N1mnW42gRJT8GY6g= -cloud.google.com/go/deploy v1.14.1/go.mod h1:N8S0b+aIHSEeSr5ORVoC0+/mOPUysVt8ae4QkZYolAw= -cloud.google.com/go/deploy v1.14.2/go.mod h1:e5XOUI5D+YGldyLNZ21wbp9S8otJbBE4i88PtO9x/2g= -cloud.google.com/go/deploy v1.15.0/go.mod h1:e5XOUI5D+YGldyLNZ21wbp9S8otJbBE4i88PtO9x/2g= -cloud.google.com/go/deploy v1.16.0/go.mod h1:e5XOUI5D+YGldyLNZ21wbp9S8otJbBE4i88PtO9x/2g= -cloud.google.com/go/deploy v1.17.0/go.mod h1:XBr42U5jIr64t92gcpOXxNrqL2PStQCXHuKK5GRUuYo= -cloud.google.com/go/deploy v1.17.1/go.mod h1:SXQyfsXrk0fBmgBHRzBjQbZhMfKZ3hMQBw5ym7MN/50= cloud.google.com/go/deploy v1.23.0 h1:Bmh5UYEeakXtjggRkjVIawXfSBbQsTgDlm96pCw9D3k= cloud.google.com/go/deploy v1.23.0/go.mod h1:O7qoXcg44Ebfv9YIoFEgYjPmrlPsXD4boYSVEiTqdHY= -cloud.google.com/go/dialogflow v1.38.0/go.mod h1:L7jnH+JL2mtmdChzAIcXQHXMvQkE3U4hTaNltEuxXn4= -cloud.google.com/go/dialogflow v1.40.0/go.mod h1:L7jnH+JL2mtmdChzAIcXQHXMvQkE3U4hTaNltEuxXn4= -cloud.google.com/go/dialogflow v1.43.0/go.mod h1:pDUJdi4elL0MFmt1REMvFkdsUTYSHq+rTCS8wg0S3+M= -cloud.google.com/go/dialogflow v1.44.0/go.mod h1:pDUJdi4elL0MFmt1REMvFkdsUTYSHq+rTCS8wg0S3+M= -cloud.google.com/go/dialogflow v1.44.1/go.mod h1:n/h+/N2ouKOO+rbe/ZnI186xImpqvCVj2DdsWS/0EAk= -cloud.google.com/go/dialogflow v1.44.2/go.mod h1:QzFYndeJhpVPElnFkUXxdlptx0wPnBWLCBT9BvtC3/c= -cloud.google.com/go/dialogflow v1.44.3/go.mod h1:mHly4vU7cPXVweuB5R0zsYKPMzy240aQdAu06SqBbAQ= -cloud.google.com/go/dialogflow v1.47.0/go.mod h1:mHly4vU7cPXVweuB5R0zsYKPMzy240aQdAu06SqBbAQ= -cloud.google.com/go/dialogflow v1.48.0/go.mod h1:mHly4vU7cPXVweuB5R0zsYKPMzy240aQdAu06SqBbAQ= -cloud.google.com/go/dialogflow v1.48.1/go.mod h1:C1sjs2/g9cEwjCltkKeYp3FFpz8BOzNondEaAlCpt+A= -cloud.google.com/go/dialogflow v1.48.2/go.mod h1:7A2oDf6JJ1/+hdpnFRfb/RjJUOh2X3rhIa5P8wQSEX4= -cloud.google.com/go/dialogflow v1.49.0/go.mod h1:dhVrXKETtdPlpPhE7+2/k4Z8FRNUp6kMV3EW3oz/fe0= cloud.google.com/go/dialogflow v1.58.0 h1:RTpoVCJHkgNLK8Co/f7F8ipyg3h8fJIaQzdaAbyg788= cloud.google.com/go/dialogflow v1.58.0/go.mod h1:sWcyFLdUrg+TWBJVq/OtwDyjcyDOfirTF0Gx12uKy7o= -cloud.google.com/go/dlp v1.10.1/go.mod h1:IM8BWz1iJd8njcNcG0+Kyd9OPnqnRNkDV8j42VT5KOI= -cloud.google.com/go/dlp v1.10.2/go.mod h1:ZbdKIhcnyhILgccwVDzkwqybthh7+MplGC3kZVZsIOQ= -cloud.google.com/go/dlp v1.10.3/go.mod h1:iUaTc/ln8I+QT6Ai5vmuwfw8fqTk2kaz0FvCwhLCom0= -cloud.google.com/go/dlp v1.11.1/go.mod h1:/PA2EnioBeXTL/0hInwgj0rfsQb3lpE3R8XUJxqUNKI= -cloud.google.com/go/dlp v1.11.2/go.mod h1:9Czi+8Y/FegpWzgSfkRlyz+jwW6Te9Rv26P3UfU/h/w= cloud.google.com/go/dlp v1.19.0 h1:AJB26PpDG0gOkf6wxQqbBXs9G+jOVnCjCagOlNiroKM= cloud.google.com/go/dlp v1.19.0/go.mod h1:cr8dKBq8un5LALiyGkz4ozcwzt3FyTlOwA4/fFzJ64c= -cloud.google.com/go/documentai v1.20.0/go.mod h1:yJkInoMcK0qNAEdRnqY/D5asy73tnPe88I1YTZT+a8E= -cloud.google.com/go/documentai v1.22.0/go.mod h1:yJkInoMcK0qNAEdRnqY/D5asy73tnPe88I1YTZT+a8E= -cloud.google.com/go/documentai v1.22.1/go.mod h1:LKs22aDHbJv7ufXuPypzRO7rG3ALLJxzdCXDPutw4Qc= -cloud.google.com/go/documentai v1.23.0/go.mod h1:LKs22aDHbJv7ufXuPypzRO7rG3ALLJxzdCXDPutw4Qc= -cloud.google.com/go/documentai v1.23.2/go.mod h1:Q/wcRT+qnuXOpjAkvOV4A+IeQl04q2/ReT7SSbytLSo= -cloud.google.com/go/documentai v1.23.4/go.mod h1:4MYAaEMnADPN1LPN5xboDR5QVB6AgsaxgFdJhitlE2Y= -cloud.google.com/go/documentai v1.23.5/go.mod h1:ghzBsyVTiVdkfKaUCum/9bGBEyBjDO4GfooEcYKhN+g= -cloud.google.com/go/documentai v1.23.6/go.mod h1:ghzBsyVTiVdkfKaUCum/9bGBEyBjDO4GfooEcYKhN+g= -cloud.google.com/go/documentai v1.23.7/go.mod h1:ghzBsyVTiVdkfKaUCum/9bGBEyBjDO4GfooEcYKhN+g= -cloud.google.com/go/documentai v1.23.8/go.mod h1:Vd/y5PosxCpUHmwC+v9arZyeMfTqBR9VIwOwIqQYYfA= -cloud.google.com/go/documentai v1.25.0/go.mod h1:ftLnzw5VcXkLItp6pw1mFic91tMRyfv6hHEY5br4KzY= cloud.google.com/go/documentai v1.34.0 h1:gmBmrTLzbpZkllu2xExISZg2Hh/ai0y605SWdheWHvI= cloud.google.com/go/documentai v1.34.0/go.mod h1:onJlbHi4ZjQTsANSZJvW7fi2M8LZJrrupXkWDcy4gLY= -cloud.google.com/go/domains v0.9.1/go.mod h1:aOp1c0MbejQQ2Pjf1iJvnVyT+z6R6s8pX66KaCSDYfE= -cloud.google.com/go/domains v0.9.2/go.mod h1:3YvXGYzZG1Temjbk7EyGCuGGiXHJwVNmwIf+E/cUp5I= -cloud.google.com/go/domains v0.9.3/go.mod h1:29k66YNDLDY9LCFKpGFeh6Nj9r62ZKm5EsUJxAl84KU= -cloud.google.com/go/domains v0.9.4/go.mod h1:27jmJGShuXYdUNjyDG0SodTfT5RwLi7xmH334Gvi3fY= -cloud.google.com/go/domains v0.9.5/go.mod h1:dBzlxgepazdFhvG7u23XMhmMKBjrkoUNaw0A8AQB55Y= cloud.google.com/go/domains v0.10.1 h1:HvZOm7Bx1fQY/MHQAbE5f8YwfJlc0NJVOGh0A0eWckc= cloud.google.com/go/domains v0.10.1/go.mod h1:RjDl3K8iq/ZZHMVqfZzRuBUr5t85gqA6LEXQBeBL5F4= -cloud.google.com/go/edgecontainer v1.1.1/go.mod h1:O5bYcS//7MELQZs3+7mabRqoWQhXCzenBu0R8bz2rwk= -cloud.google.com/go/edgecontainer v1.1.2/go.mod h1:wQRjIzqxEs9e9wrtle4hQPSR1Y51kqN75dgF7UllZZ4= -cloud.google.com/go/edgecontainer v1.1.3/go.mod h1:Ll2DtIABzEfaxaVSbwj3QHFaOOovlDFiWVDu349jSsA= -cloud.google.com/go/edgecontainer v1.1.4/go.mod h1:AvFdVuZuVGdgaE5YvlL1faAoa1ndRR/5XhXZvPBHbsE= -cloud.google.com/go/edgecontainer v1.1.5/go.mod h1:rgcjrba3DEDEQAidT4yuzaKWTbkTI5zAMu3yy6ZWS0M= cloud.google.com/go/edgecontainer v1.3.1 h1:loDGWu/sdqnCP3Xlvj4OWHL7i0wocbcLg8ApQ9BE66E= cloud.google.com/go/edgecontainer v1.3.1/go.mod h1:qyz5+Nk/UAs6kXp6wiux9I2U4A2R624K15QhHYovKKM= cloud.google.com/go/errorreporting v0.3.1 h1:E/gLk+rL7u5JZB9oq72iL1bnhVlLrnfslrgcptjJEUE= cloud.google.com/go/errorreporting v0.3.1/go.mod h1:6xVQXU1UuntfAf+bVkFk6nld41+CPyF2NSPCyXE3Ztk= -cloud.google.com/go/essentialcontacts v1.6.2/go.mod h1:T2tB6tX+TRak7i88Fb2N9Ok3PvY3UNbUsMag9/BARh4= -cloud.google.com/go/essentialcontacts v1.6.3/go.mod h1:yiPCD7f2TkP82oJEFXFTou8Jl8L6LBRPeBEkTaO0Ggo= -cloud.google.com/go/essentialcontacts v1.6.4/go.mod h1:iju5Vy3d9tJUg0PYMd1nHhjV7xoCXaOAVabrwLaPBEM= -cloud.google.com/go/essentialcontacts v1.6.5/go.mod h1:jjYbPzw0x+yglXC890l6ECJWdYeZ5dlYACTFL0U/VuM= -cloud.google.com/go/essentialcontacts v1.6.6/go.mod h1:XbqHJGaiH0v2UvtuucfOzFXN+rpL/aU5BCZLn4DYl1Q= cloud.google.com/go/essentialcontacts v1.7.1 h1:qeZAOxqWFfD7sDd1vKYaNhjGh1eckkCkSJyx/OC5egE= cloud.google.com/go/essentialcontacts v1.7.1/go.mod h1:F/MMWNLRW7b42WwWklOsnx4zrMOWDYWqWykBf1jXKPY= -cloud.google.com/go/eventarc v1.12.1/go.mod h1:mAFCW6lukH5+IZjkvrEss+jmt2kOdYlN8aMx3sRJiAI= -cloud.google.com/go/eventarc v1.13.0/go.mod h1:mAFCW6lukH5+IZjkvrEss+jmt2kOdYlN8aMx3sRJiAI= -cloud.google.com/go/eventarc v1.13.1/go.mod h1:EqBxmGHFrruIara4FUQ3RHlgfCn7yo1HYsu2Hpt/C3Y= -cloud.google.com/go/eventarc v1.13.2/go.mod h1:X9A80ShVu19fb4e5sc/OLV7mpFUKZMwfJFeeWhcIObM= -cloud.google.com/go/eventarc v1.13.3/go.mod h1:RWH10IAZIRcj1s/vClXkBgMHwh59ts7hSWcqD3kaclg= -cloud.google.com/go/eventarc v1.13.4/go.mod h1:zV5sFVoAa9orc/52Q+OuYUG9xL2IIZTbbuTHC6JSY8s= cloud.google.com/go/eventarc v1.14.1 h1:Tw1DsE1OO9NZ3LZlAtxsi4otVl5qjQ3Y3QD9dCxtAyo= cloud.google.com/go/eventarc v1.14.1/go.mod h1:NG0YicE+z9MDcmh2u4tlzLDVLRjq5UHZlibyQlPhcxY= -cloud.google.com/go/filestore v1.7.1/go.mod h1:y10jsorq40JJnjR/lQ8AfFbbcGlw3g+Dp8oN7i7FjV4= -cloud.google.com/go/filestore v1.7.2/go.mod h1:TYOlyJs25f/omgj+vY7/tIG/E7BX369triSPzE4LdgE= -cloud.google.com/go/filestore v1.7.3/go.mod h1:Qp8WaEERR3cSkxToxFPHh/b8AACkSut+4qlCjAmKTV0= -cloud.google.com/go/filestore v1.7.4/go.mod h1:S5JCxIbFjeBhWMTfIYH2Jx24J6BqjwpkkPl+nBA5DlI= -cloud.google.com/go/filestore v1.8.0/go.mod h1:S5JCxIbFjeBhWMTfIYH2Jx24J6BqjwpkkPl+nBA5DlI= -cloud.google.com/go/filestore v1.8.1/go.mod h1:MbN9KcaM47DRTIuLfQhJEsjaocVebNtNQhSLhKCF5GM= cloud.google.com/go/filestore v1.9.1 h1:s8DPPSV80FzIB7rduoMJAgknktms9hZGE3+X9KFUlK8= cloud.google.com/go/filestore v1.9.1/go.mod h1:g/FNHBABpxjL1M9nNo0nW6vLYIMVlyOKhBKtYGgcKUI= -cloud.google.com/go/firestore v1.11.0/go.mod h1:b38dKhgzlmNNGTNZZwe7ZRFEuRab1Hay3/DBsIGKKy4= -cloud.google.com/go/firestore v1.12.0/go.mod h1:b38dKhgzlmNNGTNZZwe7ZRFEuRab1Hay3/DBsIGKKy4= -cloud.google.com/go/firestore v1.13.0/go.mod h1:QojqqOh8IntInDUSTAh0c8ZsPYAr68Ma8c5DWOy8xb8= -cloud.google.com/go/firestore v1.14.0/go.mod h1:96MVaHLsEhbvkBEdZgfN+AS/GIkco1LRpH9Xp9YZfzQ= cloud.google.com/go/firestore v1.17.0 h1:iEd1LBbkDZTFsLw3sTH50eyg4qe8eoG6CjocmEXO9aQ= cloud.google.com/go/firestore v1.17.0/go.mod h1:69uPx1papBsY8ZETooc71fOhoKkD70Q1DwMrtKuOT/Y= -cloud.google.com/go/functions v1.15.1/go.mod h1:P5yNWUTkyU+LvW/S9O6V+V423VZooALQlqoXdoPz5AE= -cloud.google.com/go/functions v1.15.2/go.mod h1:CHAjtcR6OU4XF2HuiVeriEdELNcnvRZSk1Q8RMqy4lE= -cloud.google.com/go/functions v1.15.3/go.mod h1:r/AMHwBheapkkySEhiZYLDBwVJCdlRwsm4ieJu35/Ug= -cloud.google.com/go/functions v1.15.4/go.mod h1:CAsTc3VlRMVvx+XqXxKqVevguqJpnVip4DdonFsX28I= -cloud.google.com/go/functions v1.16.0/go.mod h1:nbNpfAG7SG7Duw/o1iZ6ohvL7mc6MapWQVpqtM29n8k= cloud.google.com/go/functions v1.19.1 h1:eWjTZohtJX/9rckZYXaYVViGi06JkNJRKvm0aO+ce+g= cloud.google.com/go/functions v1.19.1/go.mod h1:18RszySpwRg6aH5UTTVsRfdCwDooSf/5mvSnU7NAk4A= cloud.google.com/go/gaming v1.9.0 h1:7vEhFnZmd931Mo7sZ6pJy7uQPDxF7m7v8xtBheG08tc= -cloud.google.com/go/gaming v1.10.1/go.mod h1:XQQvtfP8Rb9Rxnxm5wFVpAp9zCQkJi2bLIb7iHGwB3s= -cloud.google.com/go/gkebackup v1.3.0/go.mod h1:vUDOu++N0U5qs4IhG1pcOnD1Mac79xWy6GoBFlWCWBU= -cloud.google.com/go/gkebackup v1.3.1/go.mod h1:vUDOu++N0U5qs4IhG1pcOnD1Mac79xWy6GoBFlWCWBU= -cloud.google.com/go/gkebackup v1.3.2/go.mod h1:OMZbXzEJloyXMC7gqdSB+EOEQ1AKcpGYvO3s1ec5ixk= -cloud.google.com/go/gkebackup v1.3.3/go.mod h1:eMk7/wVV5P22KBakhQnJxWSVftL1p4VBFLpv0kIft7I= -cloud.google.com/go/gkebackup v1.3.4/go.mod h1:gLVlbM8h/nHIs09ns1qx3q3eaXcGSELgNu1DWXYz1HI= -cloud.google.com/go/gkebackup v1.3.5/go.mod h1:KJ77KkNN7Wm1LdMopOelV6OodM01pMuK2/5Zt1t4Tvc= cloud.google.com/go/gkebackup v1.6.1 h1:bV1go067LF5XaobFXXvgW2rsuvR974ajirDjD9oXFWg= cloud.google.com/go/gkebackup v1.6.1/go.mod h1:CEnHQCsNBn+cyxcxci0qbAPYe8CkivNEitG/VAZ08ms= -cloud.google.com/go/gkeconnect v0.8.1/go.mod h1:KWiK1g9sDLZqhxB2xEuPV8V9NYzrqTUmQR9shJHpOZw= -cloud.google.com/go/gkeconnect v0.8.2/go.mod h1:6nAVhwchBJYgQCXD2pHBFQNiJNyAd/wyxljpaa6ZPrY= -cloud.google.com/go/gkeconnect v0.8.3/go.mod h1:i9GDTrfzBSUZGCe98qSu1B8YB8qfapT57PenIb820Jo= -cloud.google.com/go/gkeconnect v0.8.4/go.mod h1:84hZz4UMlDCKl8ifVW8layK4WHlMAFeq8vbzjU0yJkw= -cloud.google.com/go/gkeconnect v0.8.5/go.mod h1:LC/rS7+CuJ5fgIbXv8tCD/mdfnlAadTaUufgOkmijuk= cloud.google.com/go/gkeconnect v0.11.1 h1:X7UpDP2Qg8JfaQ6vsJeFsTo4NcrGprk9Tg4Pf7MK8Qg= cloud.google.com/go/gkeconnect v0.11.1/go.mod h1:Vu3UoOI2c0amGyv4dT/EmltzscPH41pzS4AXPqQLej0= -cloud.google.com/go/gkehub v0.14.1/go.mod h1:VEXKIJZ2avzrbd7u+zeMtW00Y8ddk/4V9511C9CQGTY= -cloud.google.com/go/gkehub v0.14.2/go.mod h1:iyjYH23XzAxSdhrbmfoQdePnlMj2EWcvnR+tHdBQsCY= -cloud.google.com/go/gkehub v0.14.3/go.mod h1:jAl6WafkHHW18qgq7kqcrXYzN08hXeK/Va3utN8VKg8= -cloud.google.com/go/gkehub v0.14.4/go.mod h1:Xispfu2MqnnFt8rV/2/3o73SK1snL8s9dYJ9G2oQMfc= -cloud.google.com/go/gkehub v0.14.5/go.mod h1:6bzqxM+a+vEH/h8W8ec4OJl4r36laxTs3A/fMNHJ0wA= cloud.google.com/go/gkehub v0.15.1 h1:VMXUz3q9Vfhe+dtSjb/yqmiDmGbcEUTuXDyk0pj2GyU= cloud.google.com/go/gkehub v0.15.1/go.mod h1:cyUwa9iFQYd/pI7IQYl6A+OF6M8uIbhmJr090v9Z4UU= -cloud.google.com/go/gkemulticloud v0.6.1/go.mod h1:kbZ3HKyTsiwqKX7Yw56+wUGwwNZViRnxWK2DVknXWfw= -cloud.google.com/go/gkemulticloud v1.0.0/go.mod h1:kbZ3HKyTsiwqKX7Yw56+wUGwwNZViRnxWK2DVknXWfw= -cloud.google.com/go/gkemulticloud v1.0.1/go.mod h1:AcrGoin6VLKT/fwZEYuqvVominLriQBCKmbjtnbMjG8= -cloud.google.com/go/gkemulticloud v1.0.2/go.mod h1:+ee5VXxKb3H1l4LZAcgWB/rvI16VTNTrInWxDjAGsGo= -cloud.google.com/go/gkemulticloud v1.0.3/go.mod h1:7NpJBN94U6DY1xHIbsDqB2+TFZUfjLUKLjUX8NGLor0= -cloud.google.com/go/gkemulticloud v1.1.0/go.mod h1:7NpJBN94U6DY1xHIbsDqB2+TFZUfjLUKLjUX8NGLor0= -cloud.google.com/go/gkemulticloud v1.1.1/go.mod h1:C+a4vcHlWeEIf45IB5FFR5XGjTeYhF83+AYIpTy4i2Q= cloud.google.com/go/gkemulticloud v1.4.0 h1:t2HXXYrICui+rZXScietjU1YdrQDLXpfqqrTo7zWSYQ= cloud.google.com/go/gkemulticloud v1.4.0/go.mod h1:rg8YOQdRKEtMimsiNCzZUP74bOwImhLRv9wQ0FwBUP4= -cloud.google.com/go/grafeas v0.3.0/go.mod h1:P7hgN24EyONOTMyeJH6DxG4zD7fwiYa5Q6GUgyFSOU8= -cloud.google.com/go/grafeas v0.3.4/go.mod h1:A5m316hcG+AulafjAbPKXBO/+I5itU4LOdKO2R/uDIc= cloud.google.com/go/grafeas v0.3.10 h1:D9uP/DjVHq9ZzCekVd+aNvQEHb3Hkwp8ki9FDnhRRJ0= cloud.google.com/go/grafeas v0.3.10/go.mod h1:Mz/AoXmxNhj74VW0fz5Idc3kMN2VZMi4UT5+UPx5Pq0= -cloud.google.com/go/gsuiteaddons v1.6.1/go.mod h1:CodrdOqRZcLp5WOwejHWYBjZvfY0kOphkAKpF/3qdZY= -cloud.google.com/go/gsuiteaddons v1.6.2/go.mod h1:K65m9XSgs8hTF3X9nNTPi8IQueljSdYo9F+Mi+s4MyU= -cloud.google.com/go/gsuiteaddons v1.6.3/go.mod h1:sCFJkZoMrLZT3JTb8uJqgKPNshH2tfXeCwTFRebTq48= -cloud.google.com/go/gsuiteaddons v1.6.4/go.mod h1:rxtstw7Fx22uLOXBpsvb9DUbC+fiXs7rF4U29KHM/pE= -cloud.google.com/go/gsuiteaddons v1.6.5/go.mod h1:Lo4P2IvO8uZ9W+RaC6s1JVxo42vgy+TX5a6hfBZ0ubs= cloud.google.com/go/gsuiteaddons v1.7.1 h1:YLh58kzaK+1Q/CHe8Cjp3hf9ZjNdJkQMavjrJUDgi9o= cloud.google.com/go/gsuiteaddons v1.7.1/go.mod h1:SxM63xEPFf0p/plgh4dP82mBSKtp2RWskz5DpVo9jh8= -cloud.google.com/go/iam v1.0.1/go.mod h1:yR3tmSL8BcZB4bxByRv2jkSIahVmCtfKZwLYGBalRE8= -cloud.google.com/go/iam v1.1.0/go.mod h1:nxdHjaKfCr7fNYx/HJMM8LgiMugmveWlkatear5gVyk= -cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= -cloud.google.com/go/iam v1.1.2/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= -cloud.google.com/go/iam v1.1.3/go.mod h1:3khUlaBXfPKKe7huYgEpDn6FtgRyMEqbkvBxrQyY5SE= -cloud.google.com/go/iam v1.1.4/go.mod h1:l/rg8l1AaA+VFMho/HYx2Vv6xinPSLMF8qfhRPIZ0L8= -cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= -cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= -cloud.google.com/go/iap v1.8.1/go.mod h1:sJCbeqg3mvWLqjZNsI6dfAtbbV1DL2Rl7e1mTyXYREQ= -cloud.google.com/go/iap v1.9.0/go.mod h1:01OFxd1R+NFrg78S+hoPV5PxEzv22HXaNqUUlmNHFuY= -cloud.google.com/go/iap v1.9.1/go.mod h1:SIAkY7cGMLohLSdBR25BuIxO+I4fXJiL06IBL7cy/5Q= -cloud.google.com/go/iap v1.9.2/go.mod h1:GwDTOs047PPSnwRD0Us5FKf4WDRcVvHg1q9WVkKBhdI= -cloud.google.com/go/iap v1.9.3/go.mod h1:DTdutSZBqkkOm2HEOTBzhZxh2mwwxshfD/h3yofAiCw= -cloud.google.com/go/iap v1.9.4/go.mod h1:vO4mSq0xNf/Pu6E5paORLASBwEmphXEjgCFg7aeNu1w= cloud.google.com/go/iap v1.10.1 h1:YF4jmMwEWXYrbfZZz024ozBXnWxUxJHzmkM6ccIzM0A= cloud.google.com/go/iap v1.10.1/go.mod h1:UKetCEzOZ4Zj7l9TSN/wzRNwbgIYzm4VM4bStaQ/tFc= -cloud.google.com/go/ids v1.4.1/go.mod h1:np41ed8YMU8zOgv53MMMoCntLTn2lF+SUzlM+O3u/jw= -cloud.google.com/go/ids v1.4.2/go.mod h1:3vw8DX6YddRu9BncxuzMyWn0g8+ooUjI2gslJ7FH3vk= -cloud.google.com/go/ids v1.4.3/go.mod h1:9CXPqI3GedjmkjbMWCUhMZ2P2N7TUMzAkVXYEH2orYU= -cloud.google.com/go/ids v1.4.4/go.mod h1:z+WUc2eEl6S/1aZWzwtVNWoSZslgzPxAboS0lZX0HjI= -cloud.google.com/go/ids v1.4.5/go.mod h1:p0ZnyzjMWxww6d2DvMGnFwCsSxDJM666Iir1bK1UuBo= cloud.google.com/go/ids v1.5.1 h1:UkHpZnlW46WulDVNtzKN+SEntZoOoHoG/Ob1GtuVCGQ= cloud.google.com/go/ids v1.5.1/go.mod h1:d/9jTtY506mTxw/nHH3UN4TFo80jhAX+tESwzj42yFo= -cloud.google.com/go/iot v1.7.1/go.mod h1:46Mgw7ev1k9KqK1ao0ayW9h0lI+3hxeanz+L1zmbbbk= -cloud.google.com/go/iot v1.7.2/go.mod h1:q+0P5zr1wRFpw7/MOgDXrG/HVA+l+cSwdObffkrpnSg= -cloud.google.com/go/iot v1.7.3/go.mod h1:t8itFchkol4VgNbHnIq9lXoOOtHNR3uAACQMYbN9N4I= -cloud.google.com/go/iot v1.7.4/go.mod h1:3TWqDVvsddYBG++nHSZmluoCAVGr1hAcabbWZNKEZLk= -cloud.google.com/go/iot v1.7.5/go.mod h1:nq3/sqTz3HGaWJi1xNiX7F41ThOzpud67vwk0YsSsqs= cloud.google.com/go/iot v1.8.1 h1:PySjOJ2Nni1IDk0LqcNhUCKOGe0yPP4rM/Nc5yA/cjI= cloud.google.com/go/iot v1.8.1/go.mod h1:FNceQ9/EGvbE2az7RGoGPY0aqrsyJO3/LqAL0h83fZw= -cloud.google.com/go/kms v1.11.0/go.mod h1:hwdiYC0xjnWsKQQCQQmIQnS9asjYVSK6jtXm+zFqXLM= -cloud.google.com/go/kms v1.12.1/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM= -cloud.google.com/go/kms v1.15.0/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM= -cloud.google.com/go/kms v1.15.2/go.mod h1:3hopT4+7ooWRCjc2DxgnpESFxhIraaI2IpAVUEhbT/w= -cloud.google.com/go/kms v1.15.3/go.mod h1:AJdXqHxS2GlPyduM99s9iGqi2nwbviBbhV/hdmt4iOQ= -cloud.google.com/go/kms v1.15.4/go.mod h1:L3Sdj6QTHK8dfwK5D1JLsAyELsNMnd3tAIwGS4ltKpc= -cloud.google.com/go/kms v1.15.5/go.mod h1:cU2H5jnp6G2TDpUGZyqTCoy1n16fbubHZjmVXSMtwDI= -cloud.google.com/go/kms v1.15.6/go.mod h1:yF75jttnIdHfGBoE51AKsD/Yqf+/jICzB9v1s1acsms= -cloud.google.com/go/kms v1.15.7/go.mod h1:ub54lbsa6tDkUwnu4W7Yt1aAIFLnspgh0kPGToDukeI= -cloud.google.com/go/language v1.10.1/go.mod h1:CPp94nsdVNiQEt1CNjF5WkTcisLiHPyIbMhvR8H2AW0= -cloud.google.com/go/language v1.11.0/go.mod h1:uDx+pFDdAKTY8ehpWbiXyQdz8tDSYLJbQcXsCkjYyvQ= -cloud.google.com/go/language v1.11.1/go.mod h1:Xyid9MG9WOX3utvDbpX7j3tXDmmDooMyMDqgUVpH17U= -cloud.google.com/go/language v1.12.1/go.mod h1:zQhalE2QlQIxbKIZt54IASBzmZpN/aDASea5zl1l+J4= -cloud.google.com/go/language v1.12.2/go.mod h1:9idWapzr/JKXBBQ4lWqVX/hcadxB194ry20m/bTrhWc= -cloud.google.com/go/language v1.12.3/go.mod h1:evFX9wECX6mksEva8RbRnr/4wi/vKGYnAJrTRXU8+f8= cloud.google.com/go/language v1.14.1 h1:lyBks2W2k7bVPvfEECH08eMOP3Vd7zkHCATt/Vy0sLM= cloud.google.com/go/language v1.14.1/go.mod h1:WaAL5ZdLLBjiorXl/8vqgb6/Fyt2qijl96c1ZP/vdc8= -cloud.google.com/go/lifesciences v0.9.1/go.mod h1:hACAOd1fFbCGLr/+weUKRAJas82Y4vrL3O5326N//Wc= -cloud.google.com/go/lifesciences v0.9.2/go.mod h1:QHEOO4tDzcSAzeJg7s2qwnLM2ji8IRpQl4p6m5Z9yTA= -cloud.google.com/go/lifesciences v0.9.3/go.mod h1:gNGBOJV80IWZdkd+xz4GQj4mbqaz737SCLHn2aRhQKM= -cloud.google.com/go/lifesciences v0.9.4/go.mod h1:bhm64duKhMi7s9jR9WYJYvjAFJwRqNj+Nia7hF0Z7JA= -cloud.google.com/go/lifesciences v0.9.5/go.mod h1:OdBm0n7C0Osh5yZB7j9BXyrMnTRGBJIZonUMxo5CzPw= cloud.google.com/go/lifesciences v0.10.1 h1:sGTR+IW9I85VhP789GMHNYOyCo7dkmvWRYh0uOfmWdo= cloud.google.com/go/lifesciences v0.10.1/go.mod h1:5D6va5/Gq3gtJPKSsE6vXayAigfOXK2eWLTdFUOTCDs= -cloud.google.com/go/logging v1.8.1/go.mod h1:TJjR+SimHwuC8MZ9cjByQulAMgni+RkXeI3wwctHJEI= -cloud.google.com/go/logging v1.9.0/go.mod h1:1Io0vnZv4onoUnsVUQY3HZ3Igb1nBchky0A0y7BBBhE= cloud.google.com/go/logging v1.12.0 h1:ex1igYcGFd4S/RZWOCU51StlIEuey5bjqwH9ZYjHibk= cloud.google.com/go/logging v1.12.0/go.mod h1:wwYBt5HlYP1InnrtYI0wtwttpVU1rifnMT7RejksUAM= -cloud.google.com/go/longrunning v0.4.2/go.mod h1:OHrnaYyLUV6oqwh0xiS7e5sLQhP1m0QU9R+WhGDMgIQ= -cloud.google.com/go/longrunning v0.5.0/go.mod h1:0JNuqRShmscVAhIACGtskSAWtqtOoPkwP0YF1oVEchc= -cloud.google.com/go/longrunning v0.5.1/go.mod h1:spvimkwdz6SPWKEt/XBij79E9fiTkHSQl/fRUUQJYJc= -cloud.google.com/go/longrunning v0.5.2/go.mod h1:nqo6DQbNV2pXhGDbDMoN2bWz68MjZUzqv2YttZiveCs= -cloud.google.com/go/longrunning v0.5.3/go.mod h1:y/0ga59EYu58J6SHmmQOvekvND2qODbu8ywBBW7EK7Y= -cloud.google.com/go/longrunning v0.5.4/go.mod h1:zqNVncI0BOP8ST6XQD1+VcvuShMmq7+xFSzOL++V0dI= -cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s= -cloud.google.com/go/managedidentities v1.6.1/go.mod h1:h/irGhTN2SkZ64F43tfGPMbHnypMbu4RB3yl8YcuEak= -cloud.google.com/go/managedidentities v1.6.2/go.mod h1:5c2VG66eCa0WIq6IylRk3TBW83l161zkFvCj28X7jn8= -cloud.google.com/go/managedidentities v1.6.3/go.mod h1:tewiat9WLyFN0Fi7q1fDD5+0N4VUoL0SCX0OTCthZq4= -cloud.google.com/go/managedidentities v1.6.4/go.mod h1:WgyaECfHmF00t/1Uk8Oun3CQ2PGUtjc3e9Alh79wyiM= -cloud.google.com/go/managedidentities v1.6.5/go.mod h1:fkFI2PwwyRQbjLxlm5bQ8SjtObFMW3ChBGNqaMcgZjI= cloud.google.com/go/managedidentities v1.7.1 h1:9hC4E7JnWn/jSUls022Sj9ri+vriGnLzvDXo0cs1zcA= cloud.google.com/go/managedidentities v1.7.1/go.mod h1:iK4qqIBOOfePt5cJR/Uo3+uol6oAVIbbG7MGy917cYM= -cloud.google.com/go/maps v1.3.0/go.mod h1:6mWTUv+WhnOwAgjVsSW2QPPECmW+s3PcRyOa9vgG/5s= -cloud.google.com/go/maps v1.4.0/go.mod h1:6mWTUv+WhnOwAgjVsSW2QPPECmW+s3PcRyOa9vgG/5s= -cloud.google.com/go/maps v1.4.1/go.mod h1:BxSa0BnW1g2U2gNdbq5zikLlHUuHW0GFWh7sgML2kIY= -cloud.google.com/go/maps v1.5.1/go.mod h1:NPMZw1LJwQZYCfz4y+EIw+SI+24A4bpdFJqdKVr0lt4= -cloud.google.com/go/maps v1.6.1/go.mod h1:4+buOHhYXFBp58Zj/K+Lc1rCmJssxxF4pJ5CJnhdz18= -cloud.google.com/go/maps v1.6.2/go.mod h1:4+buOHhYXFBp58Zj/K+Lc1rCmJssxxF4pJ5CJnhdz18= -cloud.google.com/go/maps v1.6.3/go.mod h1:VGAn809ADswi1ASofL5lveOHPnE6Rk/SFTTBx1yuOLw= -cloud.google.com/go/maps v1.6.4/go.mod h1:rhjqRy8NWmDJ53saCfsXQ0LKwBHfi6OSh5wkq6BaMhI= cloud.google.com/go/maps v1.14.0 h1:bLT2nvuOm4ye6YRgIJQ0L9zbKcbBj+TCg8k2g3c2Qlk= cloud.google.com/go/maps v1.14.0/go.mod h1:UepOes9un0UP7i8JBiaqgh8jqUaZAHVRXCYjrVlhSC8= -cloud.google.com/go/mediatranslation v0.8.1/go.mod h1:L/7hBdEYbYHQJhX2sldtTO5SZZ1C1vkapubj0T2aGig= -cloud.google.com/go/mediatranslation v0.8.2/go.mod h1:c9pUaDRLkgHRx3irYE5ZC8tfXGrMYwNZdmDqKMSfFp8= -cloud.google.com/go/mediatranslation v0.8.3/go.mod h1:F9OnXTy336rteOEywtY7FOqCk+J43o2RF638hkOQl4Y= -cloud.google.com/go/mediatranslation v0.8.4/go.mod h1:9WstgtNVAdN53m6TQa5GjIjLqKQPXe74hwSCxUP6nj4= -cloud.google.com/go/mediatranslation v0.8.5/go.mod h1:y7kTHYIPCIfgyLbKncgqouXJtLsU+26hZhHEEy80fSs= cloud.google.com/go/mediatranslation v0.9.1 h1:7X1cA4TWO0+r1RT0JTT0RE+SyO41eoFUmBDw17Oi9T8= cloud.google.com/go/mediatranslation v0.9.1/go.mod h1:vQH1amULNhSGryBjbjLb37g54rxrOwVxywS8WvUCsIU= -cloud.google.com/go/memcache v1.10.1/go.mod h1:47YRQIarv4I3QS5+hoETgKO40InqzLP6kpNLvyXuyaA= -cloud.google.com/go/memcache v1.10.2/go.mod h1:f9ZzJHLBrmd4BkguIAa/l/Vle6uTHzHokdnzSWOdQ6A= -cloud.google.com/go/memcache v1.10.3/go.mod h1:6z89A41MT2DVAW0P4iIRdu5cmRTsbsFn4cyiIx8gbwo= -cloud.google.com/go/memcache v1.10.4/go.mod h1:v/d8PuC8d1gD6Yn5+I3INzLR01IDn0N4Ym56RgikSI0= -cloud.google.com/go/memcache v1.10.5/go.mod h1:/FcblbNd0FdMsx4natdj+2GWzTq+cjZvMa1I+9QsuMA= cloud.google.com/go/memcache v1.11.1 h1:2FGuyd3WY7buNDAkMBdmeIOheNWA3gwaXrttLrEdabI= cloud.google.com/go/memcache v1.11.1/go.mod h1:3zF+dEqmEmElHuO4NtHiShekQY5okQtssjPBv7jpmZ8= -cloud.google.com/go/metastore v1.11.1/go.mod h1:uZuSo80U3Wd4zi6C22ZZliOUJ3XeM/MlYi/z5OAOWRA= -cloud.google.com/go/metastore v1.12.0/go.mod h1:uZuSo80U3Wd4zi6C22ZZliOUJ3XeM/MlYi/z5OAOWRA= -cloud.google.com/go/metastore v1.13.0/go.mod h1:URDhpG6XLeh5K+Glq0NOt74OfrPKTwS62gEPZzb5SOk= -cloud.google.com/go/metastore v1.13.1/go.mod h1:IbF62JLxuZmhItCppcIfzBBfUFq0DIB9HPDoLgWrVOU= -cloud.google.com/go/metastore v1.13.2/go.mod h1:KS59dD+unBji/kFebVp8XU/quNSyo8b6N6tPGspKszA= -cloud.google.com/go/metastore v1.13.3/go.mod h1:K+wdjXdtkdk7AQg4+sXS8bRrQa9gcOr+foOMF2tqINE= -cloud.google.com/go/metastore v1.13.4/go.mod h1:FMv9bvPInEfX9Ac1cVcRXp8EBBQnBcqH6gz3KvJ9BAE= cloud.google.com/go/metastore v1.14.1 h1:kGx+IUSSYCVn8LisCT4fpxCC9rauEVonzi7RlygdqWY= cloud.google.com/go/metastore v1.14.1/go.mod h1:WDvsAcbQLl9M4xL+eIpbKogH7aEaPWMhO9aRBcFOnJE= -cloud.google.com/go/monitoring v1.15.1/go.mod h1:lADlSAlFdbqQuwwpaImhsJXu1QSdd3ojypXrFSMr2rM= -cloud.google.com/go/monitoring v1.16.0/go.mod h1:Ptp15HgAyM1fNICAojDMoNc/wUmn67mLHQfyqbw+poY= -cloud.google.com/go/monitoring v1.16.1/go.mod h1:6HsxddR+3y9j+o/cMJH6q/KJ/CBTvM/38L/1m7bTRJ4= -cloud.google.com/go/monitoring v1.16.2/go.mod h1:B44KGwi4ZCF8Rk/5n+FWeispDXoKSk9oss2QNlXJBgc= -cloud.google.com/go/monitoring v1.16.3/go.mod h1:KwSsX5+8PnXv5NJnICZzW2R8pWTis8ypC4zmdRD63Tw= -cloud.google.com/go/monitoring v1.17.0/go.mod h1:KwSsX5+8PnXv5NJnICZzW2R8pWTis8ypC4zmdRD63Tw= -cloud.google.com/go/monitoring v1.17.1/go.mod h1:SJzPMakCF0GHOuKEH/r4hxVKF04zl+cRPQyc3d/fqII= -cloud.google.com/go/monitoring v1.18.0/go.mod h1:c92vVBCeq/OB4Ioyo+NbN2U7tlg5ZH41PZcdvfc+Lcg= cloud.google.com/go/monitoring v1.21.1 h1:zWtbIoBMnU5LP9A/fz8LmWMGHpk4skdfeiaa66QdFGc= cloud.google.com/go/monitoring v1.21.1/go.mod h1:Rj++LKrlht9uBi8+Eb530dIrzG/cU/lB8mt+lbeFK1c= -cloud.google.com/go/networkconnectivity v1.12.1/go.mod h1:PelxSWYM7Sh9/guf8CFhi6vIqf19Ir/sbfZRUwXh92E= -cloud.google.com/go/networkconnectivity v1.13.0/go.mod h1:SAnGPes88pl7QRLUen2HmcBSE9AowVAcdug8c0RSBFk= -cloud.google.com/go/networkconnectivity v1.14.0/go.mod h1:SAnGPes88pl7QRLUen2HmcBSE9AowVAcdug8c0RSBFk= -cloud.google.com/go/networkconnectivity v1.14.1/go.mod h1:LyGPXR742uQcDxZ/wv4EI0Vu5N6NKJ77ZYVnDe69Zug= -cloud.google.com/go/networkconnectivity v1.14.2/go.mod h1:5UFlwIisZylSkGG1AdwK/WZUaoz12PKu6wODwIbFzJo= -cloud.google.com/go/networkconnectivity v1.14.3/go.mod h1:4aoeFdrJpYEXNvrnfyD5kIzs8YtHg945Og4koAjHQek= -cloud.google.com/go/networkconnectivity v1.14.4/go.mod h1:PU12q++/IMnDJAB+3r+tJtuCXCfwfN+C6Niyj6ji1Po= cloud.google.com/go/networkconnectivity v1.15.1 h1:EizN+cFGHzRAyiFTK8jT1PqTo+cSnbc2IGh6OmllS7Y= cloud.google.com/go/networkconnectivity v1.15.1/go.mod h1:tYAcT4Ahvq+BiePXL/slYipf/8FF0oNJw3MqFhBnSPI= -cloud.google.com/go/networkmanagement v1.8.0/go.mod h1:Ho/BUGmtyEqrttTgWEe7m+8vDdK74ibQc+Be0q7Fof0= -cloud.google.com/go/networkmanagement v1.9.0/go.mod h1:UTUaEU9YwbCAhhz3jEOHr+2/K/MrBk2XxOLS89LQzFw= -cloud.google.com/go/networkmanagement v1.9.1/go.mod h1:CCSYgrQQvW73EJawO2QamemYcOb57LvrDdDU51F0mcI= -cloud.google.com/go/networkmanagement v1.9.2/go.mod h1:iDGvGzAoYRghhp4j2Cji7sF899GnfGQcQRQwgVOWnDw= -cloud.google.com/go/networkmanagement v1.9.3/go.mod h1:y7WMO1bRLaP5h3Obm4tey+NquUvB93Co1oh4wpL+XcU= -cloud.google.com/go/networkmanagement v1.9.4/go.mod h1:daWJAl0KTFytFL7ar33I6R/oNBH8eEOX/rBNHrC/8TA= cloud.google.com/go/networkmanagement v1.14.1 h1:0x3hVI6xbp3N/choffKPHMSxbzaPdHSD92cBElebXEk= cloud.google.com/go/networkmanagement v1.14.1/go.mod h1:3Ds8FZ3ZHjTVEedsBoZi9ef9haTE14iS6swTSqM39SI= -cloud.google.com/go/networksecurity v0.9.1/go.mod h1:MCMdxOKQ30wsBI1eI659f9kEp4wuuAueoC9AJKSPWZQ= -cloud.google.com/go/networksecurity v0.9.2/go.mod h1:jG0SeAttWzPMUILEHDUvFYdQTl8L/E/KC8iZDj85lEI= -cloud.google.com/go/networksecurity v0.9.3/go.mod h1:l+C0ynM6P+KV9YjOnx+kk5IZqMSLccdBqW6GUoF4p/0= -cloud.google.com/go/networksecurity v0.9.4/go.mod h1:E9CeMZ2zDsNBkr8axKSYm8XyTqNhiCHf1JO/Vb8mD1w= -cloud.google.com/go/networksecurity v0.9.5/go.mod h1:KNkjH/RsylSGyyZ8wXpue8xpCEK+bTtvof8SBfIhMG8= cloud.google.com/go/networksecurity v0.10.1 h1:dHN1la6xnta3E4QtWGqtc8ZAPKIZH5m8UQceIIuXZIs= cloud.google.com/go/networksecurity v0.10.1/go.mod h1:tatO1hYJ9nNChLHOFdsjex5FeqZBlPQgKdKOex7REpU= -cloud.google.com/go/notebooks v1.9.1/go.mod h1:zqG9/gk05JrzgBt4ghLzEepPHNwE5jgPcHZRKhlC1A8= -cloud.google.com/go/notebooks v1.10.0/go.mod h1:SOPYMZnttHxqot0SGSFSkRrwE29eqnKPBJFqgWmiK2k= -cloud.google.com/go/notebooks v1.10.1/go.mod h1:5PdJc2SgAybE76kFQCWrTfJolCOUQXF97e+gteUUA6A= -cloud.google.com/go/notebooks v1.11.1/go.mod h1:V2Zkv8wX9kDCGRJqYoI+bQAaoVeE5kSiz4yYHd2yJwQ= -cloud.google.com/go/notebooks v1.11.2/go.mod h1:z0tlHI/lREXC8BS2mIsUeR3agM1AkgLiS+Isov3SS70= -cloud.google.com/go/notebooks v1.11.3/go.mod h1:0wQyI2dQC3AZyQqWnRsp+yA+kY4gC7ZIVP4Qg3AQcgo= cloud.google.com/go/notebooks v1.12.1 h1:0g61C2qdWcq2p8OFH3NiLzyneS1LFfsveC5+MnpM4p8= cloud.google.com/go/notebooks v1.12.1/go.mod h1:RJCyRkLjj8UnvLEKaDl9S6//xUCa+r+d/AsxZnYBl50= -cloud.google.com/go/optimization v1.4.1/go.mod h1:j64vZQP7h9bO49m2rVaTVoNM0vEBEN5eKPUPbZyXOrk= -cloud.google.com/go/optimization v1.5.0/go.mod h1:evo1OvTxeBRBu6ydPlrIRizKY/LJKo/drDMMRKqGEUU= -cloud.google.com/go/optimization v1.5.1/go.mod h1:NC0gnUD5MWVAF7XLdoYVPmYYVth93Q6BUzqAq3ZwtV8= -cloud.google.com/go/optimization v1.6.1/go.mod h1:hH2RYPTTM9e9zOiTaYPTiGPcGdNZVnBSBxjIAJzUkqo= -cloud.google.com/go/optimization v1.6.2/go.mod h1:mWNZ7B9/EyMCcwNl1frUGEuY6CPijSkz88Fz2vwKPOY= -cloud.google.com/go/optimization v1.6.3/go.mod h1:8ve3svp3W6NFcAEFr4SfJxrldzhUl4VMUJmhrqVKtYA= cloud.google.com/go/optimization v1.7.1 h1:E3/1qRZvGxqQpapaac/EKuzusxUauXLnpirWWXXzP5k= cloud.google.com/go/optimization v1.7.1/go.mod h1:s2AjwwQEv6uExFmgS4Bf1gidI07w7jCzvvs8exqR1yk= -cloud.google.com/go/orchestration v1.8.1/go.mod h1:4sluRF3wgbYVRqz7zJ1/EUNc90TTprliq9477fGobD8= -cloud.google.com/go/orchestration v1.8.2/go.mod h1:T1cP+6WyTmh6LSZzeUhvGf0uZVmJyTx7t8z7Vg87+A0= -cloud.google.com/go/orchestration v1.8.3/go.mod h1:xhgWAYqlbYjlz2ftbFghdyqENYW+JXuhBx9KsjMoGHs= -cloud.google.com/go/orchestration v1.8.4/go.mod h1:d0lywZSVYtIoSZXb0iFjv9SaL13PGyVOKDxqGxEf/qI= -cloud.google.com/go/orchestration v1.8.5/go.mod h1:C1J7HesE96Ba8/hZ71ISTV2UAat0bwN+pi85ky38Yq8= cloud.google.com/go/orchestration v1.11.0 h1:yyi0kM47UZaJ3EEFYsBwfrkvqyPmvHwsoc3asxDmLuo= cloud.google.com/go/orchestration v1.11.0/go.mod h1:s3L89jinQaUHclqgWYw8JhBbzGSidVt5rVBxGrXeheI= -cloud.google.com/go/orgpolicy v1.11.0/go.mod h1:2RK748+FtVvnfuynxBzdnyu7sygtoZa1za/0ZfpOs1M= -cloud.google.com/go/orgpolicy v1.11.1/go.mod h1:8+E3jQcpZJQliP+zaFfayC2Pg5bmhuLK755wKhIIUCE= -cloud.google.com/go/orgpolicy v1.11.2/go.mod h1:biRDpNwfyytYnmCRWZWxrKF22Nkz9eNVj9zyaBdpm1o= -cloud.google.com/go/orgpolicy v1.11.3/go.mod h1:oKAtJ/gkMjum5icv2aujkP4CxROxPXsBbYGCDbPO8MM= -cloud.google.com/go/orgpolicy v1.11.4/go.mod h1:0+aNV/nrfoTQ4Mytv+Aw+stBDBjNf4d8fYRA9herfJI= -cloud.google.com/go/orgpolicy v1.12.0/go.mod h1:0+aNV/nrfoTQ4Mytv+Aw+stBDBjNf4d8fYRA9herfJI= -cloud.google.com/go/orgpolicy v1.12.1/go.mod h1:aibX78RDl5pcK3jA8ysDQCFkVxLj3aOQqrbBaUL2V5I= cloud.google.com/go/orgpolicy v1.14.0 h1:UuLmi1+94lIS3tCoeuinuwx4oxdx58nECiAvfwCW0SM= cloud.google.com/go/orgpolicy v1.14.0/go.mod h1:S6Pveh1JOxpSbs6+2ToJG7h3HwqC6Uf1YQ6JYG7wdM8= -cloud.google.com/go/osconfig v1.12.0/go.mod h1:8f/PaYzoS3JMVfdfTubkowZYGmAhUCjjwnjqWI7NVBc= -cloud.google.com/go/osconfig v1.12.1/go.mod h1:4CjBxND0gswz2gfYRCUoUzCm9zCABp91EeTtWXyz0tE= -cloud.google.com/go/osconfig v1.12.2/go.mod h1:eh9GPaMZpI6mEJEuhEjUJmaxvQ3gav+fFEJon1Y8Iw0= -cloud.google.com/go/osconfig v1.12.3/go.mod h1:L/fPS8LL6bEYUi1au832WtMnPeQNT94Zo3FwwV1/xGM= -cloud.google.com/go/osconfig v1.12.4/go.mod h1:B1qEwJ/jzqSRslvdOCI8Kdnp0gSng0xW4LOnIebQomA= -cloud.google.com/go/osconfig v1.12.5/go.mod h1:D9QFdxzfjgw3h/+ZaAb5NypM8bhOMqBzgmbhzWViiW8= cloud.google.com/go/osconfig v1.14.1 h1:67ISL0vZVfq0se+1cPRMYgwTjsES2k9vmSmn8ZS0O5g= cloud.google.com/go/osconfig v1.14.1/go.mod h1:Rk62nyQscgy8x4bICaTn0iWiip5EpwEfG2UCBa2TP/s= -cloud.google.com/go/oslogin v1.10.1/go.mod h1:x692z7yAue5nE7CsSnoG0aaMbNoRJRXO4sn73R+ZqAs= -cloud.google.com/go/oslogin v1.11.0/go.mod h1:8GMTJs4X2nOAUVJiPGqIWVcDaF0eniEto3xlOxaboXE= -cloud.google.com/go/oslogin v1.11.1/go.mod h1:OhD2icArCVNUxKqtK0mcSmKL7lgr0LVlQz+v9s1ujTg= -cloud.google.com/go/oslogin v1.12.1/go.mod h1:VfwTeFJGbnakxAY236eN8fsnglLiVXndlbcNomY4iZU= -cloud.google.com/go/oslogin v1.12.2/go.mod h1:CQ3V8Jvw4Qo4WRhNPF0o+HAM4DiLuE27Ul9CX9g2QdY= -cloud.google.com/go/oslogin v1.13.0/go.mod h1:xPJqLwpTZ90LSE5IL1/svko+6c5avZLluiyylMb/sRA= -cloud.google.com/go/oslogin v1.13.1/go.mod h1:vS8Sr/jR7QvPWpCjNqy6LYZr5Zs1e8ZGW/KPn9gmhws= cloud.google.com/go/oslogin v1.14.1 h1:HPPg7FWPwt7pKrbl+8VFI9UuJTbVrG2rSMHl4HkDAG4= cloud.google.com/go/oslogin v1.14.1/go.mod h1:mM/isJYnohyD3EfM12Fhy8uye46gxA1WjHRCwbkmlVw= -cloud.google.com/go/phishingprotection v0.8.1/go.mod h1:AxonW7GovcA8qdEk13NfHq9hNx5KPtfxXNeUxTDxB6I= -cloud.google.com/go/phishingprotection v0.8.2/go.mod h1:LhJ91uyVHEYKSKcMGhOa14zMMWfbEdxG032oT6ECbC8= -cloud.google.com/go/phishingprotection v0.8.3/go.mod h1:3B01yO7T2Ra/TMojifn8EoGd4G9jts/6cIO0DgDY9J8= -cloud.google.com/go/phishingprotection v0.8.4/go.mod h1:6b3kNPAc2AQ6jZfFHioZKg9MQNybDg4ixFd4RPZZ2nE= -cloud.google.com/go/phishingprotection v0.8.5/go.mod h1:g1smd68F7mF1hgQPuYn3z8HDbNre8L6Z0b7XMYFmX7I= cloud.google.com/go/phishingprotection v0.9.1 h1:oUEGd4dttG5gIUmICdCh8A1U9iVQiw0TGwvYIGQ2I7U= cloud.google.com/go/phishingprotection v0.9.1/go.mod h1:LRiflQnCpYKCMhsmhNB3hDbW+AzQIojXYr6q5+5eRQk= -cloud.google.com/go/policytroubleshooter v1.7.1/go.mod h1:0NaT5v3Ag1M7U5r0GfDCpUFkWd9YqpubBWsQlhanRv0= -cloud.google.com/go/policytroubleshooter v1.8.0/go.mod h1:tmn5Ir5EToWe384EuboTcVQT7nTag2+DuH3uHmKd1HU= -cloud.google.com/go/policytroubleshooter v1.9.0/go.mod h1:+E2Lga7TycpeSTj2FsH4oXxTnrbHJGRlKhVZBLGgU64= -cloud.google.com/go/policytroubleshooter v1.9.1/go.mod h1:MYI8i0bCrL8cW+VHN1PoiBTyNZTstCg2WUw2eVC4c4U= -cloud.google.com/go/policytroubleshooter v1.10.1/go.mod h1:5C0rhT3TDZVxAu8813bwmTvd57Phbl8mr9F4ipOsxEs= -cloud.google.com/go/policytroubleshooter v1.10.2/go.mod h1:m4uF3f6LseVEnMV6nknlN2vYGRb+75ylQwJdnOXfnv0= -cloud.google.com/go/policytroubleshooter v1.10.3/go.mod h1:+ZqG3agHT7WPb4EBIRqUv4OyIwRTZvsVDHZ8GlZaoxk= cloud.google.com/go/policytroubleshooter v1.11.1 h1:/b3wruB/KvmCpy9Jfducc8TQmM3bsoPaeCs5z7TRodA= cloud.google.com/go/policytroubleshooter v1.11.1/go.mod h1:9nJIpgQ2vloJbB8y1JkPL5vxtaSdJnJYPCUvt6PpfRs= -cloud.google.com/go/privatecatalog v0.9.1/go.mod h1:0XlDXW2unJXdf9zFz968Hp35gl/bhF4twwpXZAW50JA= -cloud.google.com/go/privatecatalog v0.9.2/go.mod h1:RMA4ATa8IXfzvjrhhK8J6H4wwcztab+oZph3c6WmtFc= -cloud.google.com/go/privatecatalog v0.9.3/go.mod h1:K5pn2GrVmOPjXz3T26mzwXLcKivfIJ9R5N79AFCF9UE= -cloud.google.com/go/privatecatalog v0.9.4/go.mod h1:SOjm93f+5hp/U3PqMZAHTtBtluqLygrDrVO8X8tYtG0= -cloud.google.com/go/privatecatalog v0.9.5/go.mod h1:fVWeBOVe7uj2n3kWRGlUQqR/pOd450J9yZoOECcQqJk= cloud.google.com/go/privatecatalog v0.10.1 h1:Ew51FHLLQsUYUDJY57eMB/mVUOoWLIji957MRw4kumw= cloud.google.com/go/privatecatalog v0.10.1/go.mod h1:mFmn5bjE9J8MEjQuu1fOc4AxOP2MoEwDLMJk04xqQCQ= -cloud.google.com/go/pubsub v1.32.0/go.mod h1:f+w71I33OMyxf9VpMVcZbnG5KSUkCOUHYpFd5U1GdRc= -cloud.google.com/go/pubsub v1.33.0/go.mod h1:f+w71I33OMyxf9VpMVcZbnG5KSUkCOUHYpFd5U1GdRc= -cloud.google.com/go/pubsub v1.34.0/go.mod h1:alj4l4rBg+N3YTFDDC+/YyFTs6JAjam2QfYsddcAW4c= -cloud.google.com/go/pubsub v1.36.1/go.mod h1:iYjCa9EzWOoBiTdd4ps7QoMtMln5NwaZQpK1hbRfBDE= cloud.google.com/go/pubsub v1.44.0 h1:pLaMJVDTlnUDIKT5L0k53YyLszfBbGoUBo/IqDK/fEI= cloud.google.com/go/pubsub v1.44.0/go.mod h1:BD4a/kmE8OePyHoa1qAHEw1rMzXX+Pc8Se54T/8mc3I= -cloud.google.com/go/pubsublite v1.8.1/go.mod h1:fOLdU4f5xldK4RGJrBMm+J7zMWNj/k4PxwEZXy39QS0= cloud.google.com/go/pubsublite v1.8.2 h1:jLQozsEVr+c6tOU13vDugtnaBSUy/PD5zK6mhm+uF1Y= cloud.google.com/go/pubsublite v1.8.2/go.mod h1:4r8GSa9NznExjuLPEJlF1VjOPOpgf3IT6k8x/YgaOPI= cloud.google.com/go/recaptchaenterprise v1.3.1 h1:u6EznTGzIdsyOsvm+Xkw0aSuKFXQlyjGE9a4exk6iNQ= -cloud.google.com/go/recaptchaenterprise/v2 v2.7.2/go.mod h1:kR0KjsJS7Jt1YSyWFkseQ756D45kaYNTlDPPaRAvDBU= -cloud.google.com/go/recaptchaenterprise/v2 v2.8.0/go.mod h1:QuE8EdU9dEnesG8/kG3XuJyNsjEqMlMzg3v3scCJ46c= -cloud.google.com/go/recaptchaenterprise/v2 v2.8.1/go.mod h1:JZYZJOeZjgSSTGP4uz7NlQ4/d1w5hGmksVgM0lbEij0= -cloud.google.com/go/recaptchaenterprise/v2 v2.8.2/go.mod h1:kpaDBOpkwD4G0GVMzG1W6Doy1tFFC97XAV3xy+Rd/pw= -cloud.google.com/go/recaptchaenterprise/v2 v2.8.3/go.mod h1:Dak54rw6lC2gBY8FBznpOCAR58wKf+R+ZSJRoeJok4w= -cloud.google.com/go/recaptchaenterprise/v2 v2.8.4/go.mod h1:Dak54rw6lC2gBY8FBznpOCAR58wKf+R+ZSJRoeJok4w= -cloud.google.com/go/recaptchaenterprise/v2 v2.9.0/go.mod h1:Dak54rw6lC2gBY8FBznpOCAR58wKf+R+ZSJRoeJok4w= -cloud.google.com/go/recaptchaenterprise/v2 v2.9.2/go.mod h1:trwwGkfhCmp05Ll5MSJPXY7yvnO0p4v3orGANAFHAuU= cloud.google.com/go/recaptchaenterprise/v2 v2.17.2 h1:tHFLYu+8w0jjjGf63D4qgVEKS9R3lw4XP4Q1P4df2g8= cloud.google.com/go/recaptchaenterprise/v2 v2.17.2/go.mod h1:iigNZOnUpf++xlm8RdMZJTX/PihYVMrHidRLjHuekec= -cloud.google.com/go/recommendationengine v0.8.1/go.mod h1:MrZihWwtFYWDzE6Hz5nKcNz3gLizXVIDI/o3G1DLcrE= -cloud.google.com/go/recommendationengine v0.8.2/go.mod h1:QIybYHPK58qir9CV2ix/re/M//Ty10OxjnnhWdaKS1Y= -cloud.google.com/go/recommendationengine v0.8.3/go.mod h1:m3b0RZV02BnODE9FeSvGv1qibFo8g0OnmB/RMwYy4V8= -cloud.google.com/go/recommendationengine v0.8.4/go.mod h1:GEteCf1PATl5v5ZsQ60sTClUE0phbWmo3rQ1Js8louU= -cloud.google.com/go/recommendationengine v0.8.5/go.mod h1:A38rIXHGFvoPvmy6pZLozr0g59NRNREz4cx7F58HAsQ= cloud.google.com/go/recommendationengine v0.9.1 h1:TQne3UMow6joFVRtTpd9kDYyYr3Jkpq+o0vJkpQgZYI= cloud.google.com/go/recommendationengine v0.9.1/go.mod h1:FfWa3OnsnDab4unvTZM2VJmvoeGn1tnntF3n+vmfyzU= -cloud.google.com/go/recommender v1.10.1/go.mod h1:XFvrE4Suqn5Cq0Lf+mCP6oBHD/yRMA8XxP5sb7Q7gpA= -cloud.google.com/go/recommender v1.11.0/go.mod h1:kPiRQhPyTJ9kyXPCG6u/dlPLbYfFlkwHNRwdzPVAoII= -cloud.google.com/go/recommender v1.11.1/go.mod h1:sGwFFAyI57v2Hc5LbIj+lTwXipGu9NW015rkaEM5B18= -cloud.google.com/go/recommender v1.11.2/go.mod h1:AeoJuzOvFR/emIcXdVFkspVXVTYpliRCmKNYDnyBv6Y= -cloud.google.com/go/recommender v1.11.3/go.mod h1:+FJosKKJSId1MBFeJ/TTyoGQZiEelQQIZMKYYD8ruK4= -cloud.google.com/go/recommender v1.12.0/go.mod h1:+FJosKKJSId1MBFeJ/TTyoGQZiEelQQIZMKYYD8ruK4= -cloud.google.com/go/recommender v1.12.1/go.mod h1:gf95SInWNND5aPas3yjwl0I572dtudMhMIG4ni8nr+0= cloud.google.com/go/recommender v1.13.1 h1:aQIUpMynK1pU1Q+EiuL7VJssLLjLwnfhL7px0vgM6xA= cloud.google.com/go/recommender v1.13.1/go.mod h1:l+n8rNMC6jZacckzLvVG/2LzKawlwAJYNO8Vl2pBlxc= -cloud.google.com/go/redis v1.13.1/go.mod h1:VP7DGLpE91M6bcsDdMuyCm2hIpB6Vp2hI090Mfd1tcg= -cloud.google.com/go/redis v1.13.2/go.mod h1:0Hg7pCMXS9uz02q+LoEVl5dNHUkIQv+C/3L76fandSA= -cloud.google.com/go/redis v1.13.3/go.mod h1:vbUpCKUAZSYzFcWKmICnYgRAhTFg9r+djWqFxDYXi4U= -cloud.google.com/go/redis v1.14.1/go.mod h1:MbmBxN8bEnQI4doZPC1BzADU4HGocHBk2de3SbgOkqs= -cloud.google.com/go/redis v1.14.2/go.mod h1:g0Lu7RRRz46ENdFKQ2EcQZBAJ2PtJHJLuiiRuEXwyQw= cloud.google.com/go/redis v1.17.1 h1:E7TeGsvyoFB+m59bqFKrQ5GSH7+uW8cUDk6Y7iqGjJ0= cloud.google.com/go/redis v1.17.1/go.mod h1:YJHeYfSoW/agIMeCvM5rszxu75mVh5DOhbu3AEZEIQM= -cloud.google.com/go/resourcemanager v1.9.1/go.mod h1:dVCuosgrh1tINZ/RwBufr8lULmWGOkPS8gL5gqyjdT8= -cloud.google.com/go/resourcemanager v1.9.2/go.mod h1:OujkBg1UZg5lX2yIyMo5Vz9O5hf7XQOSV7WxqxxMtQE= -cloud.google.com/go/resourcemanager v1.9.3/go.mod h1:IqrY+g0ZgLsihcfcmqSe+RKp1hzjXwG904B92AwBz6U= -cloud.google.com/go/resourcemanager v1.9.4/go.mod h1:N1dhP9RFvo3lUfwtfLWVxfUWq8+KUQ+XLlHLH3BoFJ0= -cloud.google.com/go/resourcemanager v1.9.5/go.mod h1:hep6KjelHA+ToEjOfO3garMKi/CLYwTqeAw7YiEI9x8= cloud.google.com/go/resourcemanager v1.10.1 h1:fO/QoSJ1lepmTM9dCbSXYWgTIhecmQkpY0mM1X9OGN0= cloud.google.com/go/resourcemanager v1.10.1/go.mod h1:A/ANV/Sv7y7fcjd4LSH7PJGTZcWRkO/69yN5UhYUmvE= -cloud.google.com/go/resourcesettings v1.6.1/go.mod h1:M7mk9PIZrC5Fgsu1kZJci6mpgN8o0IUzVx3eJU3y4Jw= -cloud.google.com/go/resourcesettings v1.6.2/go.mod h1:mJIEDd9MobzunWMeniaMp6tzg4I2GvD3TTmPkc8vBXk= -cloud.google.com/go/resourcesettings v1.6.3/go.mod h1:pno5D+7oDYkMWZ5BpPsb4SO0ewg3IXcmmrUZaMJrFic= -cloud.google.com/go/resourcesettings v1.6.4/go.mod h1:pYTTkWdv2lmQcjsthbZLNBP4QW140cs7wqA3DuqErVI= -cloud.google.com/go/resourcesettings v1.6.5/go.mod h1:WBOIWZraXZOGAgoR4ukNj0o0HiSMO62H9RpFi9WjP9I= cloud.google.com/go/resourcesettings v1.8.1 h1:whJgmR9I5V9TSZiaoCPVDgbYD1jghYoauHVfBG8TvHI= cloud.google.com/go/resourcesettings v1.8.1/go.mod h1:6V87tIXUpvJMskim6YUa+TRDTm7v6OH8FxLOIRYosl4= -cloud.google.com/go/retail v1.14.1/go.mod h1:y3Wv3Vr2k54dLNIrCzenyKG8g8dhvhncT2NcNjb/6gE= -cloud.google.com/go/retail v1.14.2/go.mod h1:W7rrNRChAEChX336QF7bnMxbsjugcOCPU44i5kbLiL8= -cloud.google.com/go/retail v1.14.3/go.mod h1:Omz2akDHeSlfCq8ArPKiBxlnRpKEBjUH386JYFLUvXo= -cloud.google.com/go/retail v1.14.4/go.mod h1:l/N7cMtY78yRnJqp5JW8emy7MB1nz8E4t2yfOmklYfg= -cloud.google.com/go/retail v1.15.1/go.mod h1:In9nSBOYhLbDGa87QvWlnE1XA14xBN2FpQRiRsUs9wU= -cloud.google.com/go/retail v1.16.0/go.mod h1:LW7tllVveZo4ReWt68VnldZFWJRzsh9np+01J9dYWzE= cloud.google.com/go/retail v1.19.0 h1:OrXxtP/asKi7vFReWmQH5kXrMRPZ2R9Zw92x8O93PMA= cloud.google.com/go/retail v1.19.0/go.mod h1:QMhO+nkvN6Mns1lu6VXmteY0I3mhwPj9bOskn6PK5aY= -cloud.google.com/go/run v1.2.0/go.mod h1:36V1IlDzQ0XxbQjUx6IYbw8H3TJnWvhii963WW3B/bo= -cloud.google.com/go/run v1.3.0/go.mod h1:S/osX/4jIPZGg+ssuqh6GNgg7syixKe3YnprwehzHKU= -cloud.google.com/go/run v1.3.1/go.mod h1:cymddtZOzdwLIAsmS6s+Asl4JoXIDm/K1cpZTxV4Q5s= -cloud.google.com/go/run v1.3.2/go.mod h1:SIhmqArbjdU/D9M6JoHaAqnAMKLFtXaVdNeq04NjnVE= -cloud.google.com/go/run v1.3.3/go.mod h1:WSM5pGyJ7cfYyYbONVQBN4buz42zFqwG67Q3ch07iK4= -cloud.google.com/go/run v1.3.4/go.mod h1:FGieuZvQ3tj1e9GnzXqrMABSuir38AJg5xhiYq+SF3o= cloud.google.com/go/run v1.6.0 h1:LRJvntufFKJ0Jcwt7BbIHwf/0Ipq4twzyJcH1qSEs84= cloud.google.com/go/run v1.6.0/go.mod h1:DXkPPa8bZ0jfRGLT+EKIlPbHvosBYBMdxTgo9EBbXZE= -cloud.google.com/go/scheduler v1.10.1/go.mod h1:R63Ldltd47Bs4gnhQkmNDse5w8gBRrhObZ54PxgR2Oo= -cloud.google.com/go/scheduler v1.10.2/go.mod h1:O3jX6HRH5eKCA3FutMw375XHZJudNIKVonSCHv7ropY= -cloud.google.com/go/scheduler v1.10.3/go.mod h1:8ANskEM33+sIbpJ+R4xRfw/jzOG+ZFE8WVLy7/yGvbc= -cloud.google.com/go/scheduler v1.10.4/go.mod h1:MTuXcrJC9tqOHhixdbHDFSIuh7xZF2IysiINDuiq6NI= -cloud.google.com/go/scheduler v1.10.5/go.mod h1:MTuXcrJC9tqOHhixdbHDFSIuh7xZF2IysiINDuiq6NI= -cloud.google.com/go/scheduler v1.10.6/go.mod h1:pe2pNCtJ+R01E06XCDOJs1XvAMbv28ZsQEbqknxGOuE= cloud.google.com/go/scheduler v1.11.1 h1:uGaM4mRrGkJ0LLBMyxD8qbvIko4y+UlSOwJQqRd/lW8= cloud.google.com/go/scheduler v1.11.1/go.mod h1:ptS76q0oOS8hCHOH4Fb/y8YunPEN8emaDdtw0D7W1VE= -cloud.google.com/go/secretmanager v1.11.1/go.mod h1:znq9JlXgTNdBeQk9TBW/FnR/W4uChEKGeqQWAJ8SXFw= -cloud.google.com/go/secretmanager v1.11.2/go.mod h1:MQm4t3deoSub7+WNwiC4/tRYgDBHJgJPvswqQVB1Vss= -cloud.google.com/go/secretmanager v1.11.3/go.mod h1:0bA2o6FabmShrEy328i67aV+65XoUFFSmVeLBn/51jI= -cloud.google.com/go/secretmanager v1.11.4/go.mod h1:wreJlbS9Zdq21lMzWmJ0XhWW2ZxgPeahsqeV/vZoJ3w= -cloud.google.com/go/secretmanager v1.11.5/go.mod h1:eAGv+DaCHkeVyQi0BeXgAHOU0RdrMeZIASKc+S7VqH4= cloud.google.com/go/secretmanager v1.14.1 h1:xlWSIg8rtBn5qCr2f3XtQP19+5COyf/ll49SEvi/0vM= cloud.google.com/go/secretmanager v1.14.1/go.mod h1:L+gO+u2JA9CCyXpSR8gDH0o8EV7i/f0jdBOrUXcIV0U= -cloud.google.com/go/security v1.15.1/go.mod h1:MvTnnbsWnehoizHi09zoiZob0iCHVcL4AUBj76h9fXA= -cloud.google.com/go/security v1.15.2/go.mod h1:2GVE/v1oixIRHDaClVbHuPcZwAqFM28mXuAKCfMgYIg= -cloud.google.com/go/security v1.15.3/go.mod h1:gQ/7Q2JYUZZgOzqKtw9McShH+MjNvtDpL40J1cT+vBs= -cloud.google.com/go/security v1.15.4/go.mod h1:oN7C2uIZKhxCLiAAijKUCuHLZbIt/ghYEo8MqwD/Ty4= -cloud.google.com/go/security v1.15.5/go.mod h1:KS6X2eG3ynWjqcIX976fuToN5juVkF6Ra6c7MPnldtc= cloud.google.com/go/security v1.18.1 h1:w7XbMR90Ir0y8NUxKJ3uyRHuHYWPUxVI5Z/sGqbrdAQ= cloud.google.com/go/security v1.18.1/go.mod h1:5P1q9rqwt0HuVeL9p61pTqQ6Lgio1c64jL2ZMWZV21Y= -cloud.google.com/go/securitycenter v1.23.0/go.mod h1:8pwQ4n+Y9WCWM278R8W3nF65QtY172h4S8aXyI9/hsQ= -cloud.google.com/go/securitycenter v1.23.1/go.mod h1:w2HV3Mv/yKhbXKwOCu2i8bCuLtNP1IMHuiYQn4HJq5s= -cloud.google.com/go/securitycenter v1.24.1/go.mod h1:3h9IdjjHhVMXdQnmqzVnM7b0wMn/1O/U20eWVpMpZjI= -cloud.google.com/go/securitycenter v1.24.2/go.mod h1:l1XejOngggzqwr4Fa2Cn+iWZGf+aBLTXtB/vXjy5vXM= -cloud.google.com/go/securitycenter v1.24.3/go.mod h1:l1XejOngggzqwr4Fa2Cn+iWZGf+aBLTXtB/vXjy5vXM= -cloud.google.com/go/securitycenter v1.24.4/go.mod h1:PSccin+o1EMYKcFQzz9HMMnZ2r9+7jbc+LvPjXhpwcU= cloud.google.com/go/securitycenter v1.35.1 h1:unUyFDeSHv89W7FPBMk10mf3R7+taAJ+1ow+0zpCzGw= cloud.google.com/go/securitycenter v1.35.1/go.mod h1:UDeknPuHWi15TaxrJCIv3aN1VDTz9nqWVUmW2vGayTo= cloud.google.com/go/servicecontrol v1.11.1 h1:d0uV7Qegtfaa7Z2ClDzr9HJmnbJW7jn0WhZ7wOX6hLE= -cloud.google.com/go/servicedirectory v1.10.1/go.mod h1:Xv0YVH8s4pVOwfM/1eMTl0XJ6bzIOSLDt8f8eLaGOxQ= -cloud.google.com/go/servicedirectory v1.11.0/go.mod h1:Xv0YVH8s4pVOwfM/1eMTl0XJ6bzIOSLDt8f8eLaGOxQ= -cloud.google.com/go/servicedirectory v1.11.1/go.mod h1:tJywXimEWzNzw9FvtNjsQxxJ3/41jseeILgwU/QLrGI= -cloud.google.com/go/servicedirectory v1.11.2/go.mod h1:KD9hCLhncWRV5jJphwIpugKwM5bn1x0GyVVD4NO8mGg= -cloud.google.com/go/servicedirectory v1.11.3/go.mod h1:LV+cHkomRLr67YoQy3Xq2tUXBGOs5z5bPofdq7qtiAw= -cloud.google.com/go/servicedirectory v1.11.4/go.mod h1:Bz2T9t+/Ehg6x+Y7Ycq5xiShYLD96NfEsWNHyitj1qM= cloud.google.com/go/servicedirectory v1.12.1 h1:LjbIXEZiyqsIADrj6Y81FnbSlaHPQHJ8UDQQnUegowc= cloud.google.com/go/servicedirectory v1.12.1/go.mod h1:d2H6joDMjnTQ4cUUCZn6k9NgZFbXjLVJbHETjoJR9k0= cloud.google.com/go/servicemanagement v1.8.0 h1:fopAQI/IAzlxnVeiKn/8WiV6zKndjFkvi+gzu+NjywY= cloud.google.com/go/serviceusage v1.6.0 h1:rXyq+0+RSIm3HFypctp7WoXxIA563rn206CfMWdqXX4= -cloud.google.com/go/shell v1.7.1/go.mod h1:u1RaM+huXFaTojTbW4g9P5emOrrmLE69KrxqQahKn4g= -cloud.google.com/go/shell v1.7.2/go.mod h1:KqRPKwBV0UyLickMn0+BY1qIyE98kKyI216sH/TuHmc= -cloud.google.com/go/shell v1.7.3/go.mod h1:cTTEz/JdaBsQAeTQ3B6HHldZudFoYBOqjteev07FbIc= -cloud.google.com/go/shell v1.7.4/go.mod h1:yLeXB8eKLxw0dpEmXQ/FjriYrBijNsONpwnWsdPqlKM= -cloud.google.com/go/shell v1.7.5/go.mod h1:hL2++7F47/IfpfTO53KYf1EC+F56k3ThfNEXd4zcuiE= cloud.google.com/go/shell v1.8.1 h1:etoJal+LB7Pn8+5vE2aAh6QcFbBmerIOh5MxNDoXykw= cloud.google.com/go/shell v1.8.1/go.mod h1:jaU7OHeldDhTwgs3+clM0KYEDYnBAPevUI6wNLf7ycE= -cloud.google.com/go/spanner v1.47.0/go.mod h1:IXsJwVW2j4UKs0eYDqodab6HgGuA1bViSqW4uH9lfUI= -cloud.google.com/go/spanner v1.49.0/go.mod h1:eGj9mQGK8+hkgSVbHNQ06pQ4oS+cyc4tXXd6Dif1KoM= -cloud.google.com/go/spanner v1.50.0/go.mod h1:eGj9mQGK8+hkgSVbHNQ06pQ4oS+cyc4tXXd6Dif1KoM= -cloud.google.com/go/spanner v1.51.0/go.mod h1:c5KNo5LQ1X5tJwma9rSQZsXNBDNvj4/n8BVc3LNahq0= -cloud.google.com/go/spanner v1.53.0/go.mod h1:liG4iCeLqm5L3fFLU5whFITqP0e0orsAW1uUSrd4rws= -cloud.google.com/go/spanner v1.53.1/go.mod h1:liG4iCeLqm5L3fFLU5whFITqP0e0orsAW1uUSrd4rws= -cloud.google.com/go/spanner v1.54.0/go.mod h1:wZvSQVBgngF0Gq86fKup6KIYmN2be7uOKjtK97X+bQU= -cloud.google.com/go/spanner v1.55.0/go.mod h1:HXEznMUVhC+PC+HDyo9YFG2Ajj5BQDkcbqB9Z2Ffxi0= -cloud.google.com/go/spanner v1.56.0/go.mod h1:DndqtUKQAt3VLuV2Le+9Y3WTnq5cNKrnLb/Piqcj+h0= -cloud.google.com/go/spanner v1.57.0/go.mod h1:aXQ5QDdhPRIqVhYmnkAdwPYvj/DRN0FguclhEWw+jOo= cloud.google.com/go/spanner v1.70.0 h1:nj6p/GJTgMDiSQ1gQ034ItsKuJgHiMOjtOlONOg8PSo= cloud.google.com/go/spanner v1.70.0/go.mod h1:X5T0XftydYp0K1adeJQDJtdWpbrOeJ7wHecM4tK6FiE= -cloud.google.com/go/speech v1.17.1/go.mod h1:8rVNzU43tQvxDaGvqOhpDqgkJTFowBpDvCJ14kGlJYo= -cloud.google.com/go/speech v1.19.0/go.mod h1:8rVNzU43tQvxDaGvqOhpDqgkJTFowBpDvCJ14kGlJYo= -cloud.google.com/go/speech v1.19.1/go.mod h1:WcuaWz/3hOlzPFOVo9DUsblMIHwxP589y6ZMtaG+iAA= -cloud.google.com/go/speech v1.19.2/go.mod h1:2OYFfj+Ch5LWjsaSINuCZsre/789zlcCI3SY4oAi2oI= -cloud.google.com/go/speech v1.20.1/go.mod h1:wwolycgONvfz2EDU8rKuHRW3+wc9ILPsAWoikBEWavY= -cloud.google.com/go/speech v1.21.0/go.mod h1:wwolycgONvfz2EDU8rKuHRW3+wc9ILPsAWoikBEWavY= -cloud.google.com/go/speech v1.21.1/go.mod h1:E5GHZXYQlkqWQwY5xRSLHw2ci5NMQNG52FfMU1aZrIA= cloud.google.com/go/speech v1.25.1 h1:iGZJS3wrdkje/Vqiacx1+r+zVwUZoXVMdklYIVsvfNw= cloud.google.com/go/speech v1.25.1/go.mod h1:WgQghvghkZ1htG6BhYn98mP7Tg0mti8dBFDLMVXH/vM= -cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= -cloud.google.com/go/storage v1.36.0/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= -cloud.google.com/go/storage v1.37.0/go.mod h1:i34TiT2IhiNDmcj65PqwCjcoUX7Z5pLzS8DEmoiFq1k= -cloud.google.com/go/storagetransfer v1.10.0/go.mod h1:DM4sTlSmGiNczmV6iZyceIh2dbs+7z2Ayg6YAiQlYfA= -cloud.google.com/go/storagetransfer v1.10.1/go.mod h1:rS7Sy0BtPviWYTTJVWCSV4QrbBitgPeuK4/FKa4IdLs= -cloud.google.com/go/storagetransfer v1.10.2/go.mod h1:meIhYQup5rg9juQJdyppnA/WLQCOguxtk1pr3/vBWzA= -cloud.google.com/go/storagetransfer v1.10.3/go.mod h1:Up8LY2p6X68SZ+WToswpQbQHnJpOty/ACcMafuey8gc= -cloud.google.com/go/storagetransfer v1.10.4/go.mod h1:vef30rZKu5HSEf/x1tK3WfWrL0XVoUQN/EPDRGPzjZs= cloud.google.com/go/storagetransfer v1.11.1 h1:Hd7H1zXGQGEWyWXxWVXDMuNCGasNQim1y9CIaMZIBX8= cloud.google.com/go/storagetransfer v1.11.1/go.mod h1:xnJo9pWysRIha8MgZxhrBEwLYbEdvdmEedhNsP5NINM= -cloud.google.com/go/talent v1.6.2/go.mod h1:CbGvmKCG61mkdjcqTcLOkb2ZN1SrQI8MDyma2l7VD24= -cloud.google.com/go/talent v1.6.3/go.mod h1:xoDO97Qd4AK43rGjJvyBHMskiEf3KulgYzcH6YWOVoo= -cloud.google.com/go/talent v1.6.4/go.mod h1:QsWvi5eKeh6gG2DlBkpMaFYZYrYUnIpo34f6/V5QykY= -cloud.google.com/go/talent v1.6.5/go.mod h1:Mf5cma696HmE+P2BWJ/ZwYqeJXEeU0UqjHFXVLadEDI= -cloud.google.com/go/talent v1.6.6/go.mod h1:y/WQDKrhVz12WagoarpAIyKKMeKGKHWPoReZ0g8tseQ= cloud.google.com/go/talent v1.7.1 h1:J3iZU+HPfoD18Lx8JsgIpwe8llQ9Fu/evcQudQCB+pk= cloud.google.com/go/talent v1.7.1/go.mod h1:X8UKtTgcP+h51MtDO/b+y3X1GxTTc7gPJ2y0aX3X1hM= -cloud.google.com/go/texttospeech v1.7.1/go.mod h1:m7QfG5IXxeneGqTapXNxv2ItxP/FS0hCZBwXYqucgSk= -cloud.google.com/go/texttospeech v1.7.2/go.mod h1:VYPT6aTOEl3herQjFHYErTlSZJ4vB00Q2ZTmuVgluD4= -cloud.google.com/go/texttospeech v1.7.3/go.mod h1:Av/zpkcgWfXlDLRYob17lqMstGZ3GqlvJXqKMp2u8so= -cloud.google.com/go/texttospeech v1.7.4/go.mod h1:vgv0002WvR4liGuSd5BJbWy4nDn5Ozco0uJymY5+U74= -cloud.google.com/go/texttospeech v1.7.5/go.mod h1:tzpCuNWPwrNJnEa4Pu5taALuZL4QRRLcb+K9pbhXT6M= cloud.google.com/go/texttospeech v1.8.1 h1:LpX9xKoGObltmT6+RGxqUeSJIq0uqPzo+fcbbOmujbY= cloud.google.com/go/texttospeech v1.8.1/go.mod h1:WoTykB+4mfSDDYPuk7smrdXNRGoJJS6dXRR6l4XqD9g= -cloud.google.com/go/tpu v1.6.1/go.mod h1:sOdcHVIgDEEOKuqUoi6Fq53MKHJAtOwtz0GuKsWSH3E= -cloud.google.com/go/tpu v1.6.2/go.mod h1:NXh3NDwt71TsPZdtGWgAG5ThDfGd32X1mJ2cMaRlVgU= -cloud.google.com/go/tpu v1.6.3/go.mod h1:lxiueqfVMlSToZY1151IaZqp89ELPSrk+3HIQ5HRkbY= -cloud.google.com/go/tpu v1.6.4/go.mod h1:NAm9q3Rq2wIlGnOhpYICNI7+bpBebMJbh0yyp3aNw1Y= -cloud.google.com/go/tpu v1.6.5/go.mod h1:P9DFOEBIBhuEcZhXi+wPoVy/cji+0ICFi4TtTkMHSSs= cloud.google.com/go/tpu v1.7.1 h1:MP2GYTVEPkg1KlhY3A4CF9Do8eklQOOfgbIYNINcVaE= cloud.google.com/go/tpu v1.7.1/go.mod h1:kgvyq1Z1yuBJSk5ihUaYxX58YMioCYg1UPuIHSxBX3M= -cloud.google.com/go/trace v1.10.1/go.mod h1:gbtL94KE5AJLH3y+WVpfWILmqgc6dXcqgNXdOPAQTYk= -cloud.google.com/go/trace v1.10.2/go.mod h1:NPXemMi6MToRFcSxRl2uDnu/qAlAQ3oULUphcHGh1vA= -cloud.google.com/go/trace v1.10.3/go.mod h1:Ke1bgfc73RV3wUFml+uQp7EsDw4dGaETLxB7Iq/r4CY= -cloud.google.com/go/trace v1.10.4/go.mod h1:Nso99EDIK8Mj5/zmB+iGr9dosS/bzWCJ8wGmE6TXNWY= -cloud.google.com/go/trace v1.10.5/go.mod h1:9hjCV1nGBCtXbAE4YK7OqJ8pmPYSxPA0I67JwRd5s3M= cloud.google.com/go/trace v1.11.1 h1:UNqdP+HYYtnm6lb91aNA5JQ0X14GnxkABGlfz2PzPew= cloud.google.com/go/trace v1.11.1/go.mod h1:IQKNQuBzH72EGaXEodKlNJrWykGZxet2zgjtS60OtjA= -cloud.google.com/go/translate v1.8.1/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= -cloud.google.com/go/translate v1.8.2/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= -cloud.google.com/go/translate v1.9.0/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= -cloud.google.com/go/translate v1.9.1/go.mod h1:TWIgDZknq2+JD4iRcojgeDtqGEp154HN/uL6hMvylS8= -cloud.google.com/go/translate v1.9.2/go.mod h1:E3Tc6rUTsQkVrXW6avbUhKJSr7ZE3j7zNmqzXKHqRrY= -cloud.google.com/go/translate v1.9.3/go.mod h1:Kbq9RggWsbqZ9W5YpM94Q1Xv4dshw/gr/SHfsl5yCZ0= -cloud.google.com/go/translate v1.10.0/go.mod h1:Kbq9RggWsbqZ9W5YpM94Q1Xv4dshw/gr/SHfsl5yCZ0= -cloud.google.com/go/translate v1.10.1/go.mod h1:adGZcQNom/3ogU65N9UXHOnnSvjPwA/jKQUMnsYXOyk= cloud.google.com/go/translate v1.12.1 h1:Vws9BGpVcaOeI6HodyWdvysUzHUBFvk7ymHu1tzFvuM= cloud.google.com/go/translate v1.12.1/go.mod h1:5f4RvC7/hh76qSl6LYuqOJaKbIzEpR1Sj+CMA6gSgIk= -cloud.google.com/go/video v1.17.1/go.mod h1:9qmqPqw/Ib2tLqaeHgtakU+l5TcJxCJbhFXM7UJjVzU= -cloud.google.com/go/video v1.19.0/go.mod h1:9qmqPqw/Ib2tLqaeHgtakU+l5TcJxCJbhFXM7UJjVzU= -cloud.google.com/go/video v1.20.0/go.mod h1:U3G3FTnsvAGqglq9LxgqzOiBc/Nt8zis8S+850N2DUM= -cloud.google.com/go/video v1.20.1/go.mod h1:3gJS+iDprnj8SY6pe0SwLeC5BUW80NjhwX7INWEuWGU= -cloud.google.com/go/video v1.20.2/go.mod h1:lrixr5JeKNThsgfM9gqtwb6Okuqzfo4VrY2xynaViTA= -cloud.google.com/go/video v1.20.3/go.mod h1:TnH/mNZKVHeNtpamsSPygSR0iHtvrR/cW1/GDjN5+GU= -cloud.google.com/go/video v1.20.4/go.mod h1:LyUVjyW+Bwj7dh3UJnUGZfyqjEto9DnrvTe1f/+QrW0= cloud.google.com/go/video v1.23.1 h1:U+fu5Jwi3q8WDDOh1hr8kcdXVUJGmP3vWsZ13jwkWFA= cloud.google.com/go/video v1.23.1/go.mod h1:ncFS3D2plMLhXkWkob/bH4bxQkubrpAlln5x7RWluXA= -cloud.google.com/go/videointelligence v1.11.1/go.mod h1:76xn/8InyQHarjTWsBR058SmlPCwQjgcvoW0aZykOvo= -cloud.google.com/go/videointelligence v1.11.2/go.mod h1:ocfIGYtIVmIcWk1DsSGOoDiXca4vaZQII1C85qtoplc= -cloud.google.com/go/videointelligence v1.11.3/go.mod h1:tf0NUaGTjU1iS2KEkGWvO5hRHeCkFK3nPo0/cOZhZAo= -cloud.google.com/go/videointelligence v1.11.4/go.mod h1:kPBMAYsTPFiQxMLmmjpcZUMklJp3nC9+ipJJtprccD8= -cloud.google.com/go/videointelligence v1.11.5/go.mod h1:/PkeQjpRponmOerPeJxNPuxvi12HlW7Em0lJO14FC3I= cloud.google.com/go/videointelligence v1.12.1 h1:4XScHLWL/1Q1FVczlxiZT+kSynUQPUktIUTqpIkOMeU= cloud.google.com/go/videointelligence v1.12.1/go.mod h1:C9bQom4KOeBl7IFPj+NiOS6WKEm1P6OOkF/ahFfE1Eg= cloud.google.com/go/vision v1.2.0 h1:/CsSTkbmO9HC8iQpxbK8ATms3OQaX3YQUeTMGCxlaK4= -cloud.google.com/go/vision/v2 v2.7.2/go.mod h1:jKa8oSYBWhYiXarHPvP4USxYANYUEdEsQrloLjrSwJU= -cloud.google.com/go/vision/v2 v2.7.3/go.mod h1:V0IcLCY7W+hpMKXK1JYE0LV5llEqVmj+UJChjvA1WsM= -cloud.google.com/go/vision/v2 v2.7.4/go.mod h1:ynDKnsDN/0RtqkKxQZ2iatv3Dm9O+HfRb5djl7l4Vvw= -cloud.google.com/go/vision/v2 v2.7.5/go.mod h1:GcviprJLFfK9OLf0z8Gm6lQb6ZFUulvpZws+mm6yPLM= -cloud.google.com/go/vision/v2 v2.7.6/go.mod h1:ZkvWTVNPBU3YZYzgF9Y1jwEbD1NBOCyJn0KFdQfE6Bw= -cloud.google.com/go/vision/v2 v2.8.0/go.mod h1:ocqDiA2j97pvgogdyhoxiQp2ZkDCyr0HWpicywGGRhU= cloud.google.com/go/vision/v2 v2.9.1 h1:jpK/E7/SJXpbnQVgfr2nGsIIzSQ9GkOsBf2iak1O8nc= cloud.google.com/go/vision/v2 v2.9.1/go.mod h1:keORalKMowhEZB5hEWi1XSVnGALMjLlRwZbDiCPFuQY= -cloud.google.com/go/vmmigration v1.7.1/go.mod h1:WD+5z7a/IpZ5bKK//YmT9E047AD+rjycCAvyMxGJbro= -cloud.google.com/go/vmmigration v1.7.2/go.mod h1:iA2hVj22sm2LLYXGPT1pB63mXHhrH1m/ruux9TwWLd8= -cloud.google.com/go/vmmigration v1.7.3/go.mod h1:ZCQC7cENwmSWlwyTrZcWivchn78YnFniEQYRWQ65tBo= -cloud.google.com/go/vmmigration v1.7.4/go.mod h1:yBXCmiLaB99hEl/G9ZooNx2GyzgsjKnw5fWcINRgD70= -cloud.google.com/go/vmmigration v1.7.5/go.mod h1:pkvO6huVnVWzkFioxSghZxIGcsstDvYiVCxQ9ZH3eYI= cloud.google.com/go/vmmigration v1.8.1 h1:dyK3bFJVx28FInAkzeLVANpChwWgAmiaUM4GNtEQS/Q= cloud.google.com/go/vmmigration v1.8.1/go.mod h1:MB7vpxl6Oz2w+CecyITUTDFkhWSMQmRTgREwkBZFyZk= -cloud.google.com/go/vmwareengine v0.4.1/go.mod h1:Px64x+BvjPZwWuc4HdmVhoygcXqEkGHXoa7uyfTgSI0= -cloud.google.com/go/vmwareengine v1.0.0/go.mod h1:Px64x+BvjPZwWuc4HdmVhoygcXqEkGHXoa7uyfTgSI0= -cloud.google.com/go/vmwareengine v1.0.1/go.mod h1:aT3Xsm5sNx0QShk1Jc1B8OddrxAScYLwzVoaiXfdzzk= -cloud.google.com/go/vmwareengine v1.0.2/go.mod h1:xMSNjIk8/itYrz1JA8nV3Ajg4L4n3N+ugP8JKzk3OaA= -cloud.google.com/go/vmwareengine v1.0.3/go.mod h1:QSpdZ1stlbfKtyt6Iu19M6XRxjmXO+vb5a/R6Fvy2y4= -cloud.google.com/go/vmwareengine v1.1.1/go.mod h1:nMpdsIVkUrSaX8UvmnBhzVzG7PPvNYc5BszcvIVudYs= cloud.google.com/go/vmwareengine v1.3.1 h1:CCdTFQnOatMPbtbMnCja//K4slk5Tjt0u3XEb1T9Qlw= cloud.google.com/go/vmwareengine v1.3.1/go.mod h1:mSYu3wnGKJqvvhIhs7VA47/A/kLoMiJz3gfQAh7cfaI= -cloud.google.com/go/vpcaccess v1.7.1/go.mod h1:FogoD46/ZU+JUBX9D606X21EnxiszYi2tArQwLY4SXs= -cloud.google.com/go/vpcaccess v1.7.2/go.mod h1:mmg/MnRHv+3e8FJUjeSibVFvQF1cCy2MsFaFqxeY1HU= -cloud.google.com/go/vpcaccess v1.7.3/go.mod h1:YX4skyfW3NC8vI3Fk+EegJnlYFatA+dXK4o236EUCUc= -cloud.google.com/go/vpcaccess v1.7.4/go.mod h1:lA0KTvhtEOb/VOdnH/gwPuOzGgM+CWsmGu6bb4IoMKk= -cloud.google.com/go/vpcaccess v1.7.5/go.mod h1:slc5ZRvvjP78c2dnL7m4l4R9GwL3wDLcpIWz6P/ziig= cloud.google.com/go/vpcaccess v1.8.1 h1:e1wJ1wQGMqOf44Gw44PU9G6NYITKm0f2We4eKzMwyEs= cloud.google.com/go/vpcaccess v1.8.1/go.mod h1:cWlLCpLOuMH8oaNmobaymgmLesasLd9w1isrKpiGwIc= -cloud.google.com/go/webrisk v1.9.1/go.mod h1:4GCmXKcOa2BZcZPn6DCEvE7HypmEJcJkr4mtM+sqYPc= -cloud.google.com/go/webrisk v1.9.2/go.mod h1:pY9kfDgAqxUpDBOrG4w8deLfhvJmejKB0qd/5uQIPBc= -cloud.google.com/go/webrisk v1.9.3/go.mod h1:RUYXe9X/wBDXhVilss7EDLW9ZNa06aowPuinUOPCXH8= -cloud.google.com/go/webrisk v1.9.4/go.mod h1:w7m4Ib4C+OseSr2GL66m0zMBywdrVNTDKsdEsfMl7X0= -cloud.google.com/go/webrisk v1.9.5/go.mod h1:aako0Fzep1Q714cPEM5E+mtYX8/jsfegAuS8aivxy3U= cloud.google.com/go/webrisk v1.10.1 h1:mYYjXXMILCwIEqtChUDNGamMBgJKnoJXa9Os2e76uzk= cloud.google.com/go/webrisk v1.10.1/go.mod h1:VzmUIag5P6V71nVAuzc7Hu0VkIDKjDa543K7HOulH/k= -cloud.google.com/go/websecurityscanner v1.6.1/go.mod h1:Njgaw3rttgRHXzwCB8kgCYqv5/rGpFCsBOvPbYgszpg= -cloud.google.com/go/websecurityscanner v1.6.2/go.mod h1:7YgjuU5tun7Eg2kpKgGnDuEOXWIrh8x8lWrJT4zfmas= -cloud.google.com/go/websecurityscanner v1.6.3/go.mod h1:x9XANObUFR+83Cya3g/B9M/yoHVqzxPnFtgF8yYGAXw= -cloud.google.com/go/websecurityscanner v1.6.4/go.mod h1:mUiyMQ+dGpPPRkHgknIZeCzSHJ45+fY4F52nZFDHm2o= -cloud.google.com/go/websecurityscanner v1.6.5/go.mod h1:QR+DWaxAz2pWooylsBF854/Ijvuoa3FCyS1zBa1rAVQ= cloud.google.com/go/websecurityscanner v1.7.1 h1:VyJObL4Pzd4ypF2814rKlesrVibrf1WpZ2yp4jJvKyw= cloud.google.com/go/websecurityscanner v1.7.1/go.mod h1:vAZ6hyqECDhgF+gyVRGzfXMrURQN5NH75Y9yW/7sSHU= -cloud.google.com/go/workflows v1.11.1/go.mod h1:Z+t10G1wF7h8LgdY/EmRcQY8ptBD/nvofaL6FqlET6g= -cloud.google.com/go/workflows v1.12.0/go.mod h1:PYhSk2b6DhZ508tj8HXKaBh+OFe+xdl0dHF/tJdzPQM= -cloud.google.com/go/workflows v1.12.1/go.mod h1:5A95OhD/edtOhQd/O741NSfIMezNTbCwLM1P1tBRGHM= -cloud.google.com/go/workflows v1.12.2/go.mod h1:+OmBIgNqYJPVggnMo9nqmizW0qEXHhmnAzK/CnBqsHc= -cloud.google.com/go/workflows v1.12.3/go.mod h1:fmOUeeqEwPzIU81foMjTRQIdwQHADi/vEr1cx9R1m5g= -cloud.google.com/go/workflows v1.12.4/go.mod h1:yQ7HUqOkdJK4duVtMeBCAOPiN1ZF1E9pAMX51vpwB/w= cloud.google.com/go/workflows v1.13.1 h1:DkxrZ4HyXvjQLZWsYAUOV1w7d2a43XscM9dmkIGmrDc= cloud.google.com/go/workflows v1.13.1/go.mod h1:xNdYtD6Sjoug+khNCAtBMK/rdh8qkjyL6aBas2XlkNc= contrib.go.opencensus.io/exporter/aws v0.0.0-20230502192102-15967c811cec h1:CSNP8nIEQt4sZEo2sGUiWSmVJ9c5QdyIQvwzZAsn+8Y= @@ -973,42 +256,14 @@ github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9 github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/Azure/azure-amqp-common-go/v3 v3.2.3 h1:uDF62mbd9bypXWi19V1bN5NZEO84JqgmI5G73ibAmrk= github.com/Azure/azure-amqp-common-go/v3 v3.2.3/go.mod h1:7rPmbSfszeovxGfc5fSAXE4ehlXQZHpMja2OtxC2Tas= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.0.0/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0/go.mod h1:ON4tFdPTwRcgWEaVDrN3584Ef+b7GgSJaXxe5fW9t4M= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0/go.mod h1:3Ug6Qzto9anB6mGlEdgYMDF5zHQ+wwhEaYR4s17PHMw= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0/go.mod h1:uReU2sSxZExRPBAg3qKzmAucSi51+SP1OhohieR821Q= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.2/go.mod h1:5FDJtLEO/GxwNgUxbwrY3LP0pEoThTQJtk2oysdXHxM= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.0/go.mod h1:a6xsAQUZg+VsS3TJ05SRp524Hs4pZ/AeFSr5ENf0Yjo= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1/go.mod h1:a6xsAQUZg+VsS3TJ05SRp524Hs4pZ/AeFSr5ENf0Yjo= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.0.0/go.mod h1:+6sju8gk8FRmSajX3Oz4G5Gm7P+mbqE9FVaXXFYTkCM= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.0/go.mod h1:NBanQUfSWiWn3QEpWDTCU0IjBECKOYvl2R8xdRtMtiM= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0/go.mod h1:1fXstnBMas5kzG+S3q8UoJcmyU6nUeunJcMDHcRYHhs= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.2/go.mod h1:aiYBYui4BJ/BJCAIKs92XiPyQfTaBWqvHujDwKb6CBU= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.2.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc= github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.7.1 h1:o/Ws6bEqMeKZUfj1RRm3mQ51O8JGU5w+Qdg2AhHib6A= github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.7.1/go.mod h1:6QAMYBAbQeeKX+REFJMZ1nFWu9XLw/PPcjYpuc9RDFs= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.6.0/go.mod h1:gZmgV+qBqygoznvqo2J9oKZAFziqhLZ2xE/WVUmzkHA= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.1.2/go.mod h1:FbdwsQ2EzwvXxOPcMFYO8ogEc9uMMIj3YkmCdXdAFmk= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0/go.mod h1:LRr2FzBTQlONPPa5HREE5+RjSCTXl7BwOvYOaWTqCaI= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/managementgroups/armmanagementgroups v1.0.0/go.mod h1:mLfWfj8v3jfWKsL9G4eoBoXVcsqcIUTapmdKy7uGOp0= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0/go.mod h1:s1tW/At+xHqjNFvWU4G0c0Qv33KOhvbGNj0RCTQDV8s= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1/go.mod h1:c/wcGeGx5FUPbM/JltUYHZcKmigwyVLJlDq+4HdtXaw= github.com/Azure/go-amqp v1.0.5 h1:po5+ljlcNSU8xtapHTe8gIc8yHxCzC03E8afH2g1ftU= github.com/Azure/go-amqp v1.0.5/go.mod h1:vZAogwdrkbyK3Mla8m/CxSc/aKdnTZ4IbPxl51Y5WZE= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest/autorest/azure/auth v0.5.13 h1:Ov8avRZi2vmrE2JcXw+tu5K/yB41r7xK9GZDiBF7NdM= github.com/Azure/go-autorest/autorest/azure/auth v0.5.13/go.mod h1:5BAVfWLWXihP47vYrPuBKKf4cS0bXI+KM9Qx6ETDJYo= github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 h1:w77/uPk80ZET2F+AfQExZyEWtn+0Rk/uw17m9fv5Ajc= github.com/Azure/go-autorest/autorest/azure/cli v0.4.6/go.mod h1:piCfgPho7BiIDdEQ1+g4VmKyD5y+p/XtSNqE6Hc4QD0= -github.com/AzureAD/microsoft-authentication-library-for-go v0.4.0/go.mod h1:Vt9sXTKwMyGcOxSmLDMnGPgqsUg7m8pe215qMLrDXw4= -github.com/AzureAD/microsoft-authentication-library-for-go v0.7.0/go.mod h1:BDJ5qMFKx9DugEg3+uQSDCdbYPr5s9vBTrL9P8TpqOU= -github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= -github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc= github.com/ClickHouse/ch-go v0.61.5 h1:zwR8QbYI0tsMiEcze/uIMK+Tz1D3XZXLdNrlaOpeEI4= github.com/ClickHouse/ch-go v0.61.5/go.mod h1:s1LJW/F/LcFs5HJnuogFMta50kKDO0lf9zzfrbl0RQg= @@ -1029,7 +284,6 @@ github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.0 h1:oVLqHXhnYtUwM89y9T1 github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.0/go.mod h1:dppbR7CwXD4pgtV9t3wD1812RaLDcBjtblcDF5f1vI0= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 h1:3c8yed4lgqTt+oTQ+JNMDo+F4xprBf+O/il4ZC0nRLw= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0/go.mod h1:obipzmGjfSjam60XLwGfqUkJsfiheAl+TUjG+4yzyPM= -github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/IBM/go-sdk-core/v5 v5.17.4 h1:VGb9+mRrnS2HpHZFM5hy4J6ppIWnwNrw0G+tLSgcJLc= github.com/IBM/go-sdk-core/v5 v5.17.4/go.mod h1:KsAAI7eStAWwQa4F96MLy+whYSh39JzNjklZRbN/8ns= github.com/IBM/ibm-cos-sdk-go v1.11.0 h1:Jp55NLN3OvBwucMGpP5wNybyjncsmTZ9+GPHai/1cE8= @@ -1038,13 +292,10 @@ github.com/IBM/sarama v1.43.2 h1:HABeEqRUh32z8yzY2hGB/j8mHSzC/HA9zlEjqFNCzSw= github.com/IBM/sarama v1.43.2/go.mod h1:Kyo4WkF24Z+1nz7xeVUFWIuKVV8RS3wM8mkvPKMdXFQ= github.com/Joker/jade v1.1.3 h1:Qbeh12Vq6BxURXT1qZBRHsDxeURB8ztcL6f3EXSGeHk= github.com/Joker/jade v1.1.3/go.mod h1:T+2WLyt7VH6Lp0TRxQrUYEs64nRc83wkMQrfeIQKduM= -github.com/KimMachineGun/automemlimit v0.6.0/go.mod h1:T7xYht7B8r6AG/AqFcUdc7fzd2bIdBKmepfP2S1svPY= github.com/KimMachineGun/automemlimit v0.6.1 h1:ILa9j1onAAMadBsyyUJv5cack8Y1WT26yLj/V+ulKp8= github.com/KimMachineGun/automemlimit v0.6.1/go.mod h1:T7xYht7B8r6AG/AqFcUdc7fzd2bIdBKmepfP2S1svPY= -github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/MicahParks/keyfunc/v2 v2.1.0 h1:6ZXKb9Rp6qp1bDbJefnG7cTH8yMN1IC/4nf+GVjO99k= github.com/MicahParks/keyfunc/v2 v2.1.0/go.mod h1:rW42fi+xgLJ2FRRXAfNx9ZA8WpD4OeE/yHVMteCkw9k= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM= github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ= @@ -1060,26 +311,19 @@ github.com/Shopify/sarama v1.38.1/go.mod h1:iwv9a67Ha8VNa+TifujYoWGxWnu2kNVAQdSd github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/agnivade/levenshtein v1.2.0 h1:U9L4IOT0Y3i0TIlUIDJ7rVUziKi/zPbrJGaFrtYH3SY= github.com/agnivade/levenshtein v1.2.0/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU= github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9 h1:7kQgkwGRoLzC9K0oyXdJo7nve/bynv/KwUsxbiTlzAM= github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19 h1:iXUgAaqDcIUGbRoy2TdeofRG/j1zpGRSEmNK05T+bi8= github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b h1:slYM766cy2nI3BwyRiyQj/Ud48djTMtMebDqepE95rw= -github.com/alecthomas/assert/v2 v2.2.2/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ= -github.com/alecthomas/assert/v2 v2.3.0/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ= github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek= github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s= github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY= github.com/alecthomas/kong v0.8.0 h1:ryDCzutfIqJPnNn0omnrgHLbAggDQM2VWHikE1xqK7s= github.com/alecthomas/kong v0.8.0/go.mod h1:n1iCIO2xS46oE8ZfYCNDqdR0b0wZNrXAIAqro/2132U= -github.com/alecthomas/participle/v2 v2.0.0/go.mod h1:rAKZdJldHu8084ojcWevWAL8KmEU+AT+Olodb+WoN2Y= -github.com/alecthomas/participle/v2 v2.1.0/go.mod h1:Y1+hAs8DHPmc3YUFzqllV+eSQ9ljPTk0ZkPMtEdAx2c= github.com/alecthomas/participle/v2 v2.1.1 h1:hrjKESvSqGHzRb4yW1ciisFJ4p3MGYih6icjJvbsmV8= github.com/alecthomas/participle/v2 v2.1.1/go.mod h1:Y1+hAs8DHPmc3YUFzqllV+eSQ9ljPTk0ZkPMtEdAx2c= -github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= -github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/alexflint/go-arg v1.4.2 h1:lDWZAXxpAnZUq4qwb86p/3rIJJ2Li81EoMbTMujhVa0= github.com/alexflint/go-arg v1.4.2/go.mod h1:9iRbDxne7LcR/GSvEr7ma++GLpdIU1zrghf2y2768kM= github.com/alexflint/go-scalar v1.0.0 h1:NGupf1XV/Xb04wXskDFzS0KWOLH632W/EO4fAFi+A70= @@ -1088,7 +332,6 @@ github.com/alicebob/miniredis v2.5.0+incompatible h1:yBHoLpsyjupjz3NL3MhKMVkR41j github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk= github.com/aliyun/aliyun-oss-go-sdk v2.2.10+incompatible h1:ROMcuN61gI8SfQ+AEMh4d7GZ3gwTZLIhPjtd05TQCG4= github.com/aliyun/aliyun-oss-go-sdk v2.2.10+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= -github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= @@ -1099,21 +342,12 @@ github.com/apache/arrow/go/arrow v0.0.0-20211112161151-bc219186db40 h1:q4dksr6IC github.com/apache/arrow/go/arrow v0.0.0-20211112161151-bc219186db40/go.mod h1:Q7yQnSMnLvcXlZ8RV+jwz/6y1rQTqbX6C82SndT52Zs= github.com/apache/arrow/go/v10 v10.0.1 h1:n9dERvixoC/1JjDmBcs9FPaEryoANa2sCgVFo6ez9cI= github.com/apache/arrow/go/v11 v11.0.0 h1:hqauxvFQxww+0mEU/2XHG6LT7eZternCZq+A5Yly2uM= -github.com/apache/arrow/go/v12 v12.0.0/go.mod h1:d+tV/eHZZ7Dz7RPrFKtPK02tpr+c9/PEd/zm8mDS9Vg= -github.com/apache/arrow/go/v12 v12.0.1/go.mod h1:weuTY7JvTG/HDPtMQxEUp7pU73vkLWMLpY67QwZ/WWw= -github.com/apache/arrow/go/v14 v14.0.2/go.mod h1:u3fgh3EdgN/YQ8cVQRguVW3R+seMybFg8QBQ5LU+eBY= github.com/apache/arrow/go/v15 v15.0.2 h1:60IliRbiyTWCWjERBCkO1W4Qun9svcYoZrSLcyOsMLE= github.com/apache/arrow/go/v15 v15.0.2/go.mod h1:DGXsR3ajT524njufqf95822i+KTh+yea1jass9YXgjA= -github.com/apache/thrift v0.17.0/go.mod h1:OLxhMRJxomX+1I/KUw03qoV3mMz16BwaKI+d4fPBx7Q= github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3 h1:ZSTrOEhiM5J5RFxEaFvMZVEAM1KvT1YzbEOwB2EAGjA= github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e h1:QEF07wC0T1rKkctt1RINW/+RMTVmiwxETico2l3gxJA= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 h1:G1bPvciwNyF7IUmKXNt9Ak3m6u9DE1rF+RmtIkBpVdA= -github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= -github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= -github.com/aws/aws-sdk-go v1.51.25/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= -github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= -github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o= github.com/aws/aws-sdk-go-v2/service/kms v1.35.3 h1:UPTdlTOwWUX49fVi7cymEN6hDqCwe3LNv1vi7TXUutk= github.com/aws/aws-sdk-go-v2/service/kms v1.35.3/go.mod h1:gjDP16zn+WWalyaUqwCCioQ8gU8lzttCCc9jYsiQI/8= github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.32.4 h1:NgRFYyFpiMD62y4VPXh4DosPFbZd4vdMVBWKk0VmWXc= @@ -1124,7 +358,6 @@ github.com/aws/aws-sdk-go-v2/service/sqs v1.34.3 h1:Vjqy5BZCOIsn4Pj8xzyqgGmsSqzz github.com/aws/aws-sdk-go-v2/service/sqs v1.34.3/go.mod h1:L0enV3GCRd5iG9B64W35C4/hwsCB00Ib+DKVGTadKHI= github.com/aws/aws-sdk-go-v2/service/ssm v1.52.4 h1:hgSBvRT7JEWx2+vEGI9/Ld5rZtl7M5lu8PqdvOmbRHw= github.com/aws/aws-sdk-go-v2/service/ssm v1.52.4/go.mod h1:v7NIzEFIHBiicOMaMTuEmbnzGnqW0d+6ulNALul6fYE= -github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/baidubce/bce-sdk-go v0.9.188 h1:8MA7ewe4VpX01uYl7Kic6ZvfIReUFdSKbY46ZqlQM7U= @@ -1154,38 +387,26 @@ github.com/bytedance/sonic v1.10.0-rc3 h1:uNSnscRapXTwUgTyOF0GVljYD08p9X/Lbr9Mwe github.com/bytedance/sonic v1.10.0-rc3/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/campoy/embedmd v1.0.0 h1:V4kI2qTJJLf4J29RzI/MAt2c3Bl4dQSYPuflzwFH2hY= github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8= -github.com/casbin/casbin/v2 v2.37.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= -github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo= github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= -github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= -github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs= +github.com/chromedp/cdproto v0.0.0-20220208224320-6efb837e6bc2/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U= github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic= github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww= -github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY= github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= -github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic= github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= -github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= -github.com/cilium/ebpf v0.9.1/go.mod h1:+OhNOIXx/Fnu1IE8bJz2dzOA+VSfyTfdNUVdlQnxUFY= github.com/cilium/ebpf v0.11.0 h1:V8gS/bTCCjX9uUnkUFUpPsksM8n1lXBAvHcpiFk1X2Y= github.com/cilium/ebpf v0.11.0/go.mod h1:WE7CZAnqOL2RouJ4f1uyNhqr2P4CCvXFIqdRDUgWsVs= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible h1:C29Ae4G5GtYyYMm1aztcyj/J5ckgJm2zwdDajFbx1NY= github.com/circonus-labs/circonusllhist v0.1.3 h1:TJH+oke8D16535+jHExHj4nQvzlZrj7ug5D7I/orNUA= -github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk= -github.com/cncf/xds/go v0.0.0-20230428030218-4003588d1b74/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c h1:2zRrJWIt/f9c9HhNHAgrRgq0San5gRRUJTBXLkchal0= github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA= github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= @@ -1195,7 +416,6 @@ github.com/coder/quartz v0.1.0 h1:cLL+0g5l7xTf6ordRnUMMiZtRE8Sq5LxpghS63vEXrQ= github.com/coder/quartz v0.1.0/go.mod h1:vsiCc+AHViMKH2CQpGIpFgdHIEQsxwm8yCscqKmzbRA= github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo= github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= -github.com/containerd/cgroups/v3 v3.0.1/go.mod h1:/vtwk1VXrtoa5AaZLkypuOJgA/6DyPMZHJPGQNtlHnw= github.com/containerd/cgroups/v3 v3.0.3 h1:S5ByHZ/h9PMe5IOQoN7E+nMc2UcLEM/V48DGDJ9kip0= github.com/containerd/cgroups/v3 v3.0.3/go.mod h1:8HBe7V3aWGLFPd/k03swSIsGjZhHI2WzJmticMgVuz0= github.com/containerd/containerd v1.6.18 h1:qZbsLvmyu+Vlty0/Ex5xc0z2YtKpIsb5n45mAMI+2Ns= @@ -1216,7 +436,6 @@ github.com/couchbase/ghistogram v0.1.0/go.mod h1:s1Jhy76zqfEecpNWJfWUiKZookAFaiG github.com/couchbase/moss v0.2.0 h1:VCYrMzFwEryyhRSeI+/b3tRBSeTpi/8gn5Kf6dxqn+o= github.com/couchbase/moss v0.2.0/go.mod h1:9MaHIaRuy9pvLPUJxB8sh8OrLfyDczECVL37grCIubs= github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= -github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/creasty/defaults v1.8.0 h1:z27FJxCAa0JKt3utc0sCImAEb+spPucmKoOdLHvHYKk= @@ -1245,7 +464,6 @@ github.com/dave/courtney v0.3.0 h1:8aR1os2ImdIQf3Zj4oro+lD/L4Srb5VwGefqZ/jzz7U= github.com/dave/courtney v0.3.0/go.mod h1:BAv3hA06AYfNUjfjQr+5gc6vxeBVOupLqrColj+QSD8= github.com/dave/gopackages v0.0.0-20170318123100-46e7023ec56e h1:l99YKCdrK4Lvb/zTupt0GMPfNbncAGf8Cv/t1sYLOg0= github.com/dave/gopackages v0.0.0-20170318123100-46e7023ec56e/go.mod h1:i00+b/gKdIDIxuLDFob7ustLAVqhsZRk2qVZrArELGQ= -github.com/dave/jennifer v1.6.0/go.mod h1:AxTG893FiZKqxy3FP1kL80VMshSMuz2G+EgvszgGRnk= github.com/dave/kerr v0.0.0-20170318121727-bc25dd6abe8e h1:xURkGi4RydhyaYR6PzcyHTueQudxY4LgxN1oYEPJHa0= github.com/dave/kerr v0.0.0-20170318121727-bc25dd6abe8e/go.mod h1:qZqlPyPvfsDJt+3wHJ1EvSXDuVjFTK0j2p/ca+gtsb8= github.com/dave/patsy v0.0.0-20210517141501-957256f50cba h1:1o36L4EKbZzazMk8iGC4kXpVnZ6TPxR2mZ9qVKjNNAs= @@ -1257,13 +475,10 @@ github.com/dchest/uniuri v1.2.0/go.mod h1:fSzm4SLHzNZvWLvWJew423PhAzkpNQYq+uNLq4 github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3 h1:tkum0XDgfR0jcVVXuTsYv/erY2NnEDqwRojbxR1rBYA= github.com/dgryski/go-sip13 v0.0.0-20190329191031-25c5027a8c7b h1:Yqiad0+sloMPdd/0Fg22actpFx0dekpzt1xJmVNVkU0= github.com/dhui/dktest v0.3.0 h1:kwX5a7EkLcjo7VpsPQSYJcKGbXBXdjI9FGjuUj1jn6I= -github.com/digitalocean/godo v1.113.0/go.mod h1:Z2mTP848Vi3IXXl5YbPekUgr4j4tOePomA+OE1Ag98w= github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= -github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E= github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= -github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= @@ -1288,48 +503,30 @@ github.com/eapache/go-resiliency v1.6.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6 github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 h1:Oy0F4ALJ04o5Qqpdz8XLIpNA3WM/iSIXqxtqo7UGVws= github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= -github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q= github.com/efficientgo/tools/core v0.0.0-20220225185207-fe763185946b h1:ZHiD4/yE4idlbqvAO6iYCOYRzOMRpxkW+FKasRA3tsQ= github.com/efficientgo/tools/core v0.0.0-20220225185207-fe763185946b/go.mod h1:OmVcnJopJL8d3X3sSXTiypGoUSgFq1aDGmlrdi9dn/M= github.com/elastic/go-sysinfo v1.11.2 h1:mcm4OSYVMyws6+n2HIVMGkln5HOpo5Ie1ZmbbNn0jg4= github.com/elastic/go-sysinfo v1.11.2/go.mod h1:GKqR8bbMK/1ITnez9NIsIfXQr25aLhRJa7AfT8HpBFQ= github.com/elastic/go-windows v1.0.1 h1:AlYZOldA+UJ0/2nBuqWdo90GFCgG9xuyw9SYzGUtJm0= github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss= +github.com/elazarl/goproxy v1.3.0/go.mod h1:X/5W/t+gzDyLfHW4DrMdpjqYjpXsURlBt9lpBDxZZZQ= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw= -github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q= -github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g= -github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0= -github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= -github.com/envoyproxy/protoc-gen-validate v1.0.1/go.mod h1:0vj8bNkYbSTNS2PIyH87KZaeN4x9zpL9Qt8fQC7d+vs= -github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= -github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= -github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/felixge/fgprof v0.9.4 h1:ocDNwMFlnA0NU0zSB3I52xkO4sFXk80VK9lXjLClu88= github.com/felixge/fgprof v0.9.4/go.mod h1:yKl+ERSa++RYOs32d8K6WEXCB4uXdLls4ZaZPpayhMM= -github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/flosch/pongo2/v4 v4.0.2 h1:gv+5Pe3vaSVmiJvh/BZa82b7/00YUGm0PIyVVLop0Hw= github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8= github.com/fluent/fluent-bit-go v0.0.0-20230731091245-a7a013e2473c h1:yKN46XJHYC/gvgH2UsisJ31+n4K3S7QYZSfU2uAWjuI= github.com/fluent/fluent-bit-go v0.0.0-20230731091245-a7a013e2473c/go.mod h1:L92h+dgwElEyUuShEwjbiHjseW410WIcNz+Bjutc8YQ= github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8= github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk= -github.com/franela/goblin v0.0.0-20210519012713-85d372ac71e2/go.mod h1:VzmDKDJVZI3aJmnRI9VjAn9nJ8qPPsN1fqzr9dqInIo= -github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= -github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= -github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fsouza/fake-gcs-server v1.7.0 h1:Un0BXUXrRWYSmYyC1Rqm2e2WJfTPyDy/HGMz31emTi8= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= -github.com/getkin/kin-openapi v0.125.0/go.mod h1:wb1aSZA/iWmorQP9KTAS/phLj/t17B5jT7+fS8ed9NM= github.com/getkin/kin-openapi v0.126.0 h1:c2cSgLnAsS0xYfKsgt5oBV6MYRM/giU8/RtwUY4wyfY= github.com/getkin/kin-openapi v0.126.0/go.mod h1:7mONz8IwmSRg6RttPu6v8U/OJ+gr+J99qSFNjPGSQqw= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= @@ -1348,14 +545,11 @@ github.com/go-fonts/liberation v0.3.2/go.mod h1:N0QsDLVUQPy3UYg9XAc3Uh3UDMp2Z7M1 github.com/go-fonts/stix v0.1.0 h1:UlZlgrvvmT/58o573ot7NFw0vZasZ5I6bcIft/oMdgg= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe6ZudgnXrq0barxBImvnnJoMEhXAzcbM0I= -github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= github.com/go-kit/kit v0.13.0 h1:OoneCcHKHQ03LfBpoQCUfCluwd2Vt3ohz+kvbJneZAU= github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4FKDg= github.com/go-latex/latex v0.0.0-20231108140139-5c1ce85aa4ea h1:DfZQkvEbdmOe+JK2TMtBM+0I9GSdzE2y/L1/AmD8xKc= github.com/go-latex/latex v0.0.0-20231108140139-5c1ce85aa4ea/go.mod h1:Y7Vld91/HRbTBm7JwoI7HejdDB0u+e9AUBO9MB7yuZk= -github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= @@ -1372,20 +566,13 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4= github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= -github.com/go-resty/resty/v2 v2.12.0/go.mod h1:o0yGPrkS3lOe1+eFajk6kBW8ScXzwU3hD69/gt2yB/0= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= +github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 h1:TQcrn6Wq+sKGkpyPvppOz99zsMBaUOKXq6HSv655U1c= github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= -github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= -github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= -github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= github.com/goccmack/gocc v0.0.0-20230228185258-2292f9e40198 h1:FSii2UQeSLngl3jFoR4tUKZLprO7qUlh/TKKticc0BM= github.com/goccmack/gocc v0.0.0-20230228185258-2292f9e40198/go.mod h1:DTh/Y2+NbnOVVoypCCQrovMPDKUGp4yZpSbWg5D0XIM= -github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/goccy/go-yaml v1.9.8/go.mod h1:JubOolP3gh0HpiBc4BLRD4YmjEjHAmIIB2aaXKkTfoE= github.com/goccy/go-yaml v1.11.0 h1:n7Z+zx8S9f9KgzG6KtQKf+kwqXZlLNR2F6018Dgau54= github.com/goccy/go-yaml v1.11.0/go.mod h1:H+mJrWtjPTJAHvRbV09MCK9xYwODM+wRTVFFTWckfng= github.com/gocql/gocql v0.0.0-20200526081602-cd04bd7f22a7 h1:TvUE5vjfoa7fFHMlmGOk0CsauNj1w4yJjR9+/GnWVCw= @@ -1397,14 +584,8 @@ github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c= github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= -github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= -github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/glog v1.2.3/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= -github.com/golang/glog v1.2.4/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12 h1:uK3X/2mt4tbSGoHvbLBHUny7CKiuwUip3MArtukol4E= github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= github.com/gomodule/redigo v1.8.9 h1:Sl3u+2BI/kk+VEatbj0scLdrFhjPmbxOc1myhDP41ws= @@ -1412,118 +593,88 @@ github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs0 github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/cel-go v0.22.0/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8= -github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= github.com/google/go-jsonnet v0.18.0 h1:/6pTy6g+Jh1a1I2UMoAODkqELFiVIdOxbNwv0DDzoOg= github.com/google/go-jsonnet v0.18.0/go.mod h1:C3fTzyVJDslXdiTqw/bTFk7vSGyCtH3MGRbDfvEwGd0= -github.com/google/go-pkcs11 v0.2.0/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY= -github.com/google/go-pkcs11 v0.2.1-0.20230907215043-c6f79328ddf9/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY= github.com/google/go-pkcs11 v0.3.0 h1:PVRnTgtArZ3QQqTGtbtjtnIkzl2iY2kt24yqbrf7td8= github.com/google/go-pkcs11 v0.3.0/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY= -github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= -github.com/google/pprof v0.0.0-20240416155748-26353dc0451f/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA= github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg= github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4= -github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/cloud-bigtable-clients-test v0.0.2 h1:S+sCHWAiAc+urcEnvg5JYJUOdlQEm/SEzQ/c/IdAH5M= github.com/googleapis/cloud-bigtable-clients-test v0.0.2/go.mod h1:mk3CrkrouRgtnhID6UZQDK3DrFFa7cYCAJcEmNsHYrY= -github.com/googleapis/enterprise-certificate-proxy v0.2.4/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= -github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= -github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= -github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc= -github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= github.com/googleapis/gnostic v0.3.0 h1:CcQijm0XKekKjP/YCz28LXVSpgguuB+nCxaSjCe09y0= github.com/googleapis/go-type-adapters v1.0.0 h1:9XdMn+d/G57qq1s8dNc5IesGCXHf6V2HZ2JwRxfA2tA= github.com/googleapis/google-cloud-go-testing v0.0.0-20210719221736-1c9a4c676720 h1:zC34cGQu69FG7qzJ3WiKW244WfhDC3xxYMeNOX2gtUQ= github.com/googleapis/google-cloud-go-testing v0.0.0-20210719221736-1c9a4c676720/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gophercloud/gophercloud v1.11.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grafana/alerting v0.0.0-20250129195454-3e5b80036b7a/go.mod h1:QsnoKX/iYZxA4Cv+H+wC7uxutBD8qi8ZW5UJvD2TYmU= +github.com/grafana/authlib v0.0.0-20250123104008-e99947858901/go.mod h1:/gYfphsNu9v1qYWXxpv1NSvMEMSwvdf8qb8YlgwIRl8= github.com/grafana/authlib/types v0.0.0-20250120144156-d6737a7dc8f5/go.mod h1:qYjSd1tmJiuVoSICp7Py9/zD54O9uQQA3wuM6Gg4DFM= +github.com/grafana/authlib/types v0.0.0-20250120145936-5f0e28e7a87c/go.mod h1:qYjSd1tmJiuVoSICp7Py9/zD54O9uQQA3wuM6Gg4DFM= github.com/grafana/cloudflare-go v0.0.0-20230110200409-c627cf6792f2 h1:qhugDMdQ4Vp68H0tp/0iN17DM2ehRo1rLEdOFe/gB8I= github.com/grafana/cloudflare-go v0.0.0-20230110200409-c627cf6792f2/go.mod h1:w/aiO1POVIeXUQyl0VQSZjl5OAGDTL5aX+4v0RA1tcw= github.com/grafana/cog v0.0.23 h1:/0CCJ24Z8XXM2DnboSd2FzoIswUroqIZzVr8oJWmMQs= github.com/grafana/cog v0.0.23/go.mod h1:jrS9indvWuDs60RHEZpLaAkmZdgyoLKMOEUT0jiB1t0= -github.com/grafana/cue v0.0.0-20230926092038-971951014e3f/go.mod h1:okjJBHFQFer+a41sAe2SaGm1glWS8oEb6CmJvn5Zdws= github.com/grafana/go-gelf/v2 v2.0.1 h1:BOChP0h/jLeD+7F9mL7tq10xVkDG15he3T1zHuQaWak= github.com/grafana/go-gelf/v2 v2.0.1/go.mod h1:lexHie0xzYGwCgiRGcvZ723bSNyNI8ZRD4s0CLobh90= +github.com/grafana/grafana-plugin-sdk-go v0.263.0/go.mod h1:U43Cnrj/9DNYyvFcNdeUWNjMXTKNB0jcTcQGpWKd2gw= +github.com/grafana/grafana/apps/advisor v0.0.0-20250123151950-b066a6313173/go.mod h1:goSDiy3jtC2cp8wjpPZdUHRENcoSUHae1/Px/MDfddA= github.com/grafana/grafana/apps/advisor v0.0.0-20250220154326-6e5de80ef295/go.mod h1:9I1dKV3Dqr0NPR9Af0WJGxOytp5/6W3JLiNChOz8r+c= +github.com/grafana/grafana/apps/alerting/notifications v0.0.0-20250121113133-e747350fee2d/go.mod h1:AvleS6icyPmcBjihtx5jYEvdzLmHGBp66NuE0AMR57A= +github.com/grafana/grafana/apps/investigation v0.0.0-20250121113133-e747350fee2d/go.mod h1:HQprw3MmiYj5OUV9CZnkwA1FKDZBmYACuAB3oDvUOmI= +github.com/grafana/grafana/apps/playlist v0.0.0-20250121113133-e747350fee2d/go.mod h1:DjJe5osrW/BKrzN9hAAOSElNWutj1bcriExa7iDP7kA= +github.com/grafana/grafana/pkg/aggregator v0.0.0-20250121113133-e747350fee2d/go.mod h1:1sq0guad+G4SUTlBgx7SXfhnzy7D86K/LcVOtiQCiMA= github.com/grafana/grafana/pkg/build v0.0.0-20250220114259-be81314e2118/go.mod h1:STVpVboMYeBAfyn6Zw6XHhTHqUxzMy7pzRiVgk1l0W0= -github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A= -github.com/grafana/saml v0.4.15-0.20240523142256-cc370b98af7c/go.mod h1:S4+611dxnKt8z/ulbvaJzcgSHsuhjVc1QHNTcr1R7Fw= +github.com/grafana/grafana/pkg/semconv v0.0.0-20250121113133-e747350fee2d/go.mod h1:tfLnBpPYgwrBMRz4EXqPCZJyCjEG4Ev37FSlXnocJ2c= +github.com/grafana/grafana/pkg/storage/unified/apistore v0.0.0-20250121113133-e747350fee2d/go.mod h1:CXpwZ3Mkw6xVlGKc0SqUxqXCP3Uv182q6qAQnLaLxRg= github.com/grafana/tail v0.0.0-20230510142333-77b18831edf0 h1:bjh0PVYSVVFxzINqPFYJmAmJNrWPgnVjuSdYJGHmtFU= github.com/grafana/tail v0.0.0-20230510142333-77b18831edf0/go.mod h1:7t5XR+2IA8P2qggOAHTj/GCZfoLBle3OvNSYh1VkRBU= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= github.com/hamba/avro/v2 v2.27.0 h1:IAM4lQ0VzUIKBuo4qlAiLKfqALSrFC+zi1iseTtbBKU= github.com/hamba/avro/v2 v2.27.0/go.mod h1:jN209lopfllfrz7IGoZErlDz+AyUJ3vrBePQFZwYf5I= -github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= -github.com/hashicorp/consul/api v1.28.2/go.mod h1:KyzqzgMEya+IZPcD65YFoOVAgPpbfERu4I/tzG6/ueE= -github.com/hashicorp/consul/sdk v0.16.0/go.mod h1:7pxqqhqoaPqnBnzXD1StKed62LqJeClzVsUEy85Zr0A= -github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-msgpack/v2 v2.1.1 h1:xQEY9yB2wnHitoSzk/B9UjXWRQ67QKu5AOm8aFp8N3I= github.com/hashicorp/go-msgpack/v2 v2.1.1/go.mod h1:upybraOAblm4S7rx0+jeNy+CWWhzywQsSRV5033mMu4= -github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= -github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= -github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-plugin v1.6.2/go.mod h1:CkgLQ5CZqNmdL9U9JzM532t8ZiYQ35+pj3b1FD37R0Q= github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE= -github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1 h1:sNCoNyDEvN1xa+X0baata4RdcpKwcMS6DH+xwfqPgjw= -github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= -github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= github.com/hashicorp/mdns v1.0.4 h1:sY0CMhFmjIPDMlTB+HfymFHCaYLhgifZ0QhjaYKD/UQ= -github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= -github.com/hashicorp/nomad/api v0.0.0-20240418183417-ea5f2f6748c7/go.mod h1:svtxn6QnrQ69P23VvIWMR34tg3vmwLz4UdUzm1dSCgE= github.com/hashicorp/raft v1.7.0 h1:4u24Qn6lQ6uwziM++UgsyiT64Q8GyRn43CV41qPiz1o= github.com/hashicorp/raft v1.7.0/go.mod h1:N1sKh6Vn47mrWvEArQgILTyng8GoDRNYlgKyK7PMjs0= github.com/hashicorp/raft-wal v0.4.1 h1:aU8XZ6x8R9BAIB/83Z1dTDtXvDVmv9YVYeXxd/1QBSA= github.com/hashicorp/raft-wal v0.4.1/go.mod h1:A6vP5o8hGOs1LHfC1Okh9xPwWDcmb6Vvuz/QyqUXlOE= -github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/heroku/x v0.0.61 h1:yfoAAtnFWSFZj+UlS+RZL/h8QYEp1R4wHVEg0G+Hwh4= github.com/heroku/x v0.0.61/go.mod h1:C7xYbpMdond+s6L5VpniDUSVPRwm3kZum1o7XiD5ZHk= -github.com/hetznercloud/hcloud-go/v2 v2.7.2/go.mod h1:49tIV+pXRJTUC7fbFZ03s45LKqSQdOPP5y91eOnJo/k= -github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= -github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo= github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= -github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/ianlancetaylor/demangle v0.0.0-20240312041847-bd984b5ce465 h1:KwWnWVWCNtNq/ewIX7HIKnELmEx2nDP42yskD/pi7QE= github.com/ianlancetaylor/demangle v0.0.0-20240312041847-bd984b5ce465/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= -github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/influxdata/influxdb v1.7.7 h1:UvNzAPfBrKMENVbQ4mr4ccA9sW+W1Ihl0Yh1s0BiVAg= -github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/influxdata/tdigest v0.0.2-0.20210216194612-fc98d27c9e8b h1:i44CesU68ZBRvtCjBi3QSosCIKrjmMbYlQMFAwVLds4= github.com/influxdata/tdigest v0.0.2-0.20210216194612-fc98d27c9e8b/go.mod h1:Z0kXnxzbTC2qrx4NaIzYkE1k66+6oEDQTvL95hQFh5Y= github.com/influxdata/telegraf v1.16.3 h1:x0qeuSGGMg5y+YqP/5ZHwXZu3bcBrO8AAQOTNlYEb1c= github.com/influxdata/telegraf v1.16.3/go.mod h1:fX/6k7qpIqzVPWyeIamb0wN5hbwc0ANUaTS80lPYFB8= -github.com/ionos-cloud/sdk-go/v6 v6.1.11/go.mod h1:EzEgRIDxBELvfoa/uBN0kOQaqovLjUWEB7iW4/Q+t4k= +github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= github.com/iris-contrib/schema v0.0.6 h1:CPSBLyx2e91H2yJzPuhGuifVRnZBBJ3pCOMbOvPZaTw= github.com/iris-contrib/schema v0.0.6/go.mod h1:iYszG0IOsuIsfzjymw1kMzTL8YQcCWlm65f3wX8J5iA= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc= @@ -1532,16 +683,12 @@ github.com/jackspirou/syscerts v0.0.0-20160531025014-b68f5469dff1 h1:9Xm8CKtMZIX github.com/jackspirou/syscerts v0.0.0-20160531025014-b68f5469dff1/go.mod h1:zuHl3Hh+e9P6gmBPvcqR1HjkaWHC/csgyskg6IaFKFo= github.com/jaegertracing/jaeger v1.57.0 h1:3wDtUUPs6NRYH7+d+y8MilDkLHdpPrVlQ2wbcsA62bs= github.com/jaegertracing/jaeger v1.57.0/go.mod h1:p/1fxIU9hKHl7qEhKC72p2ZYVhvvZvNB73y6V7YyuTs= -github.com/jarcoal/httpmock v1.3.0/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg= -github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg= github.com/jedib0t/go-pretty/v6 v6.2.4 h1:wdaj2KHD2W+mz8JgJ/Q6L/T5dB7kyqEFI16eLq7GEmk= github.com/jedib0t/go-pretty/v6 v6.2.4/go.mod h1:+nE9fyyHGil+PuISTCrp7avEdo6bqoMwqZnuiK2r2a0= github.com/jeremywohl/flatten v1.0.1 h1:LrsxmB3hfwJuE+ptGOijix1PIfOoKLJ3Uee/mzbgtrs= github.com/jeremywohl/flatten v1.0.1/go.mod h1:4AmD/VxjWcI5SRB0n6szE2A6s2fsNHDLO0nAlMHgfLQ= -github.com/jessevdk/go-flags v1.4.1-0.20181029123624-5de817a9aa20/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jhump/gopoet v0.1.0 h1:gYjOPnzHd2nzB37xYQZxj4EIQNpBrBskRqQQ3q4ZgSg= github.com/jhump/goprotoc v0.5.0 h1:Y1UgUX+txUznfqcGdDef8ZOVlyQvnV0pKWZH08RmZuo= -github.com/jmattheis/goverter v1.4.0/go.mod h1:iVIl/4qItWjWj2g3vjouGoYensJbRqDHpzlEVMHHFeY= github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4= github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= @@ -1576,14 +723,9 @@ github.com/kevinmbeaulieu/eq-go v1.0.0/go.mod h1:G3S8ajA56gKBZm4UB9AOyoOS37JO3ro github.com/kisielk/errcheck v1.5.0 h1:e8esj/e4R+SAOwFwN+n3zr0nYeCyeweozKfO23MvHzY= github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46 h1:veS9QfglfvqAw2e+eeNT/SbGySq8ajECXJ9e4fPoLhY= -github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s= github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4= -github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/knadh/koanf v1.5.0 h1:q2TSd/3Pyc/5yP9ldIrSdIz26MCcyNQzW0pEAugLPNs= @@ -1599,20 +741,18 @@ github.com/labstack/echo/v4 v4.11.1 h1:dEpLU2FLg4UVmvCGPuk/APjlH6GDpbEPti61srUUU github.com/labstack/echo/v4 v4.11.1/go.mod h1:YuYRTSM3CHs2ybfrL8Px48bO6BAnYIN4l8wSTMP6BDQ= github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= -github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs= github.com/leodido/go-syslog/v4 v4.1.0 h1:Wsl194qyWXr7V6DrGWC3xmxA9Ra6XgWO+toNt2fmCaI= github.com/leodido/go-syslog/v4 v4.1.0/go.mod h1:eJ8rUfDN5OS6dOkCOBYlg2a+hbAg6pJa99QXXgMrd98= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/leodido/ragel-machinery v0.0.0-20190525184631-5f46317e436b h1:11UHH39z1RhZ5dc4y4r/4koJo6IYFgTRMe/LlwRTEw0= github.com/leodido/ragel-machinery v0.0.0-20190525184631-5f46317e436b/go.mod h1:WZxr2/6a/Ar9bMDc2rN/LJrE/hF6bXE4LPyDSIxwAfg= -github.com/linode/linodego v1.32.0/go.mod h1:y8GDP9uLVH4jTB9qyrgw79qfKdYJmNCGUOJmfuiOcmI= +github.com/linkedin/goavro/v2 v2.10.0/go.mod h1:UgQUb2N/pmueQYH9bfqFioWxzYCZXSfF8Jw03O5sjqA= github.com/logrusorgru/aurora/v3 v3.0.0 h1:R6zcoZZbvVcGMvDCKo45A9U/lzYyzl5NfYIvznmDfE4= github.com/logrusorgru/aurora/v3 v3.0.0/go.mod h1:vsR12bk5grlLvLXAYrBsb5Oc/N+LxAlxggSjiwMnCUc= github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c h1:VtwQ41oftZwlMnOEbMWQtSEUgU64U4s+GHk7hZK+jtY= github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE= github.com/lyft/protoc-gen-star v0.6.1 h1:erE0rdztuaDq3bpGifD95wfoPrSZc95nGA6tbiNYh6M= -github.com/lyft/protoc-gen-star/v2 v2.0.3/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= github.com/lyft/protoc-gen-star/v2 v2.0.4-0.20230330145011-496ad1ac90a4 h1:sIXJOMrYnQZJu7OB7ANSF4MYri2fTEGIsRLz6LwI4xE= github.com/lyft/protoc-gen-star/v2 v2.0.4-0.20230330145011-496ad1ac90a4/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= github.com/mailgun/raymond/v2 v2.0.48 h1:5dmlB680ZkFG2RN/0lvTAghrSxIESeu9/2aeDqACtjw= @@ -1621,19 +761,12 @@ github.com/matryer/moq v0.3.3 h1:pScMH9VyrdT4S93yiLpVyU8rCDqGQr24uOyBxmktG5Q= github.com/matryer/moq v0.3.3/go.mod h1:RJ75ZZZD71hejp39j4crZLsEDszGk6iH4v4YsWFKH4s= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= -github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= -github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM= github.com/mfridman/xflag v0.1.0 h1:TWZrZwG1QklFX5S4j1vxfF1sZbZeZSGofMwPMLAF29M= github.com/mfridman/xflag v0.1.0/go.mod h1:/483ywM5ZO5SuMVjrIGquYNE5CzLrj5Ux/LxWWnjRaE= github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg= github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE= -github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= -github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk= -github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= -github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/mitchellh/cli v1.1.5 h1:OxRIeJXpAMztws/XHlN2vu6imG5Dpq+j61AzAX5fLng= @@ -1641,34 +774,20 @@ github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2Em github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= -github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/gox v0.4.0 h1:lfGJxY7ToLJQjHHwi0EX6uYBdK78egf954SQl13PQJc= github.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY= -github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mithrandie/readline-csvq v1.3.0 h1:VTJEOGouJ8j27jJCD4kBBbNTxM0OdBvE1aY1tMhlqE8= github.com/mithrandie/readline-csvq v1.3.0/go.mod h1:FKyYqDgf/G4SNov7SMFXRWO6LQLXIOeTog/NB97FZl0= -github.com/moby/moby v25.0.2+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc= -github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= -github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= -github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= -github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= -github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/mostynb/go-grpc-compression v1.2.3 h1:42/BKWMy0KEJGSdWvzqIyOZ95YcR9mLPqKctH7Uo//I= github.com/mostynb/go-grpc-compression v1.2.3/go.mod h1:AghIxF3P57umzqM9yz795+y1Vjs47Km/Y2FE6ouQ7Lg= github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8 h1:P48LjvUQpTReR3TQRbxSeSBsMXzfK0uol7eRcr7VBYQ= github.com/natessilva/dag v0.0.0-20180124060714-7194b8dcc5c4 h1:dnMxwus89s86tI8rcGVp2HwZzlz7c5o92VOy7dSckBQ= -github.com/nats-io/jwt v1.2.2/go.mod h1:/xX356yQA6LuXI9xWW7mZNpxgF2mBmGecH+Fj34sP5Q= -github.com/nats-io/jwt/v2 v2.0.3/go.mod h1:VRP+deawSXyhNjXmxPCHskrR6Mq50BqpEI5SEcNiGlY= -github.com/nats-io/nats-server/v2 v2.5.0/go.mod h1:Kj86UtrXAL6LwYRA6H4RqzkHhK0Vcv2ZnKD5WbQ1t3g= -github.com/nats-io/nats.go v1.12.1/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w= github.com/nats-io/nats.go v1.34.0 h1:fnxnPCNiwIG5w08rlMcEKTUw4AV/nKyGCOJE8TdhSPk= github.com/nats-io/nats.go v1.34.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= -github.com/nats-io/nkeys v0.2.0/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s= -github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI= github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= @@ -1680,45 +799,6 @@ github.com/ncw/swift/v2 v2.0.2/go.mod h1:z0A9RVdYPjNjXVo2pDOPxZ4eu3oarO1P91fTItc github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/nsf/jsondiff v0.0.0-20230430225905-43f6cf3098c1 h1:dOYG7LS/WK00RWZc8XGgcUTlTxpp3mKhdR2Q9z9HbXM= github.com/nsf/jsondiff v0.0.0-20230430225905-43f6cf3098c1/go.mod h1:mpRZBD8SJ55OIICQ3iWH0Yz3cjzA61JdqMLoWXeB2+8= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= -github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk= -github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8AyFNU9d0= -github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo= -github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw= -github.com/onsi/ginkgo/v2 v2.7.0/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo= -github.com/onsi/ginkgo/v2 v2.8.1/go.mod h1:N1/NbDngAFcSLdyZ+/aYTYGSlq9qMCS/cNKGJjy+csc= -github.com/onsi/ginkgo/v2 v2.9.0/go.mod h1:4xkjoL/tZv4SMWeww56BU5kAt19mVB47gTWxmrTcxyk= -github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo= -github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts= -github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= -github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0= -github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= -github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= -github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= -github.com/onsi/gomega v1.21.1/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc= -github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM= -github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg= -github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM= -github.com/onsi/gomega v1.26.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM= -github.com/onsi/gomega v1.27.1/go.mod h1:aHX5xOykVYzWOV4WqQy0sy8BQptgukenXpCXfadcIAw= -github.com/onsi/gomega v1.27.3/go.mod h1:5vG284IBtfDAmDyrK+eGyZmUgUlmi+Wngqo557cZ6Gw= -github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= -github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4= -github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ= -github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= -github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= -github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/open-telemetry/opentelemetry-collector-contrib/exporter/kafkaexporter v0.102.0 h1:R70PpK14trQfL/Vj5oAiGRqX09s2gOWuf6t1Ae5fevQ= github.com/open-telemetry/opentelemetry-collector-contrib/exporter/kafkaexporter v0.102.0/go.mod h1:xmy/yFFmB1Epy+czrYMbA+4xeOKvhFqNqYWU6qINeis= github.com/open-telemetry/opentelemetry-collector-contrib/exporter/zipkinexporter v0.102.0 h1:N3vWsp3xealy4AX8TovfHG5EKi/k7z+F/8LFP4SVAgo= @@ -1757,16 +837,12 @@ github.com/open-telemetry/opentelemetry-collector-contrib/receiver/opencensusrec github.com/open-telemetry/opentelemetry-collector-contrib/receiver/opencensusreceiver v0.102.0/go.mod h1:WNFjuquVqyi+WEoa6L0J3DzPLRsP24ZlbZYwKv49VwY= github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zipkinreceiver v0.102.0 h1:Pemo9pZa3VMYdrM/bss3f0qqVyBzPSulOBQL8VQcgN8= github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zipkinreceiver v0.102.0/go.mod h1:fvjAM+jOQdiXCmAENKH/eWxBBqTaImbq3lpoBI4X5Ek= -github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa4YDFlwRYAMyE= -github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= github.com/oschwald/geoip2-golang v1.11.0 h1:hNENhCn1Uyzhf9PTmquXENiWS6AlxAEnBII6r8krA3w= github.com/oschwald/geoip2-golang v1.11.0/go.mod h1:P9zG+54KPEFOliZ29i7SeYZ/GM6tfEL+rgSn03hYuUo= github.com/oschwald/maxminddb-golang v1.13.0 h1:R8xBorY71s84yO06NgTmQvqvTvlS/bnYZrrWX1MElnU= github.com/oschwald/maxminddb-golang v1.13.0/go.mod h1:BU0z8BfFVhi1LQaonTwwGQlsHUEu9pWNdMfmq4ztm0o= -github.com/ovh/go-ovh v1.4.3/go.mod h1:AkPXVtgwB6xlKblMjRKJJmjRp+ogrE7fz2lVgcQY8SY= github.com/parquet-go/parquet-go v0.23.0 h1:dyEU5oiHCtbASyItMCD2tXtT2nPmoPbKpqf0+nnGrmk= github.com/parquet-go/parquet-go v0.23.0/go.mod h1:MnwbUcFHU6uBYMymKAlPPAw9yh3kE1wWl6Gl1uLdkNk= github.com/paulmach/orb v0.11.1 h1:3koVegMC4X/WeiXYz9iswopaTwMem53NzTJuTF20JzU= @@ -1776,17 +852,11 @@ github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhM github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30 h1:BHT1/DKsYDGkUgQ2jmMaozVcdk+sVfz0+1ZJq4zkWgw= github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= -github.com/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6h/4HXRGUiZiufxo49BM= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phpdave11/gofpdf v1.4.2 h1:KPKiIbfwbvC/wOncwhrpRdXVj2CZTCFlw4wnoyjtHfQ= -github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I= -github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= -github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= -github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo= github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk= github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= @@ -1794,15 +864,10 @@ github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c h1:NRoLoZvkB github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/pquerna/cachecontrol v0.1.0 h1:yJMy84ti9h/+OEWa752kBTKv4XC30OtVVHYv/8cTqKc= github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI= -github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= -github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= -github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U= github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= github.com/prometheus/common/assets v0.2.0 h1:0P5OrzoHrYBOSM1OigWL3mY8ZvV2N4zIE/5AahrSrfM= -github.com/prometheus/prometheus v0.52.0/go.mod h1:3z74cVsmVH0iXOR5QBjB7Pa6A0KJeEAK5A6UsmAFb1g= github.com/prometheus/statsd_exporter v0.26.0 h1:SQl3M6suC6NWQYEzOvIv+EF6dAMYEqIuZy+o4H9F5Ig= github.com/prometheus/statsd_exporter v0.26.0/go.mod h1:GXFLADOmBTVDrHc7b04nX8ooq3azG61pnECNqT7O5DM= github.com/rabbitmq/amqp091-go v1.9.0 h1:qrQtyzB4H8BQgEuJwhmVQqVHB9O4+MNDJCCAcpc3Aoo= @@ -1818,13 +883,11 @@ github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99 github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245 h1:K1Xf3bKttbF+koVGaX5xngRIZ5bVjbmPnaxE/dR08uY= -github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.2+incompatible h1:C89EOx/XBWwIXl8wm8OPJBd7kPF25UfsK2X7Ph/zCAk= github.com/sagikazarmark/crypt v0.19.0 h1:WMyLTjHBo64UvNcWqpzY3pbZTYgnemZU8FBZigKc42E= github.com/sagikazarmark/crypt v0.19.0/go.mod h1:c6vimRziqqERhtSe0MhIvzE1w54FrCHtrXb5NH/ja78= github.com/samuel/go-zookeeper v0.0.0-20190810000440-0ceca61e4d75 h1:cA+Ubq9qEVIQhIWvP2kNuSZ2CmnfBJFSRq+kO1pu2cc= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.26/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg= github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiyyjYS17cCYRqP13/SHk= github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= github.com/schollz/progressbar/v3 v3.14.6 h1:GyjwcWBAf+GFDMLziwerKvpuS7ZF+mNTAXIB2aspiZs= @@ -1837,24 +900,16 @@ github.com/shirou/gopsutil/v4 v4.24.0-alpha.1 h1:lLPAdP4TpfgJ5byoc3EFwNSKZj8kCnD github.com/shirou/gopsutil/v4 v4.24.0-alpha.1/go.mod h1:GVpYUxBee6CTWux2/JslZ7fYPwqkQ8YDJSXmGAryYy4= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= -github.com/shoenig/test v1.7.1/go.mod h1:UxJ6u/x2v/TNs/LoLxBNJRV9DiwBBKYxXSyczsBHFoI= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= -github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad h1:fiWzISvDn0Csy5H0iwgAuJGQTUpVfEMJJd4nRFXogbc= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stoewer/parquet-cli v0.0.7 h1:rhdZODIbyMS3twr4OM3am8BPPT5pbfMcHLH93whDM5o= github.com/stoewer/parquet-cli v0.0.7/go.mod h1:bskxHdj8q3H1EmfuCqjViFoeO3NEvs5lzZAQvI8Nfjk= -github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/handy v0.0.0-20200128134331-0f66f006fb2e/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/substrait-io/substrait v0.57.1 h1:GW8nnYfSowMseHR8Os82/X6lNtQGIK7p4p+lr6r+auw= github.com/substrait-io/substrait v0.57.1/go.mod h1:q9s+tjo+gK0lsA+SqYB0lhojNuxvdPdfYlGUP0hjbrA= -github.com/substrait-io/substrait-go v0.4.2/go.mod h1:qhpnLmrcvAnlZsUyPXZRqldiHapPTXC3t7xFgDi3aQg= github.com/substrait-io/substrait-go v1.2.0 h1:3ZNRkc8FYD7ifCagKEOZQtUcgMceMQfwo2N1NGaK4Q4= github.com/substrait-io/substrait-go v1.2.0/go.mod h1:IPsy24rdjp/buXR+T8ENl6QCnSCS6h+uM8P+GaZez7c= github.com/tdewolff/minify/v2 v2.12.8 h1:Q2BqOTmlMjoutkuD/OPCnJUpIqrzT3nRPkw+q+KpXS0= @@ -1888,7 +943,6 @@ github.com/uber-go/atomic v1.4.0 h1:yOuPqEq4ovnhEjpHmfFwsqBXDYbQeT6Nb0bwD6XnD5o= github.com/uber-go/atomic v1.4.0/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/vburenin/ifacemaker v1.2.1/go.mod h1:5WqrzX2aD7/hi+okBjcaEQJMg4lDGrpuEX3B8L4Wgrs= github.com/vertica/vertica-sql-go v1.3.3 h1:fL+FKEAEy5ONmsvya2WH5T8bhkvY27y/Ik3ReR2T+Qw= github.com/vertica/vertica-sql-go v1.3.3/go.mod h1:jnn2GFuv+O2Jcjktb7zyc4Utlbu9YVqpHH/lx63+1M4= github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= @@ -1928,13 +982,8 @@ github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRK github.com/zenazn/goji v1.0.1 h1:4lbD8Mx2h7IvloP7r2C0D6ltZP6Ufip8Hn0wmSK5LR8= github.com/zenazn/goji v1.0.1/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b h1:7gd+rd8P3bqcn/96gOZa3F5dpJr/vEiDQYlNb/y2uNs= -go.einride.tech/aip v0.66.0/go.mod h1:qAhMsfT7plxBX+Oy7Huol6YUvZ0ZzdUz26yZsQwfl1M= go.einride.tech/aip v0.68.0 h1:4seM66oLzTpz50u4K1zlJyOXQ3tCzcJN7I22tKkjipw= go.einride.tech/aip v0.68.0/go.mod h1:7y9FF8VtPWqpxuAxl0KQWqaULxW4zFIesD6zF5RIHHg= -go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= -go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= go.etcd.io/gofail v0.1.0 h1:XItAMIhOojXFQMgrxjnd2EIIHun/d5qL0Pf7FzVTkFg= go.etcd.io/gofail v0.1.0/go.mod h1:VZBCXYGZhHAinaBiiqYvuDynvahNsAyLFwB3kEHKz1M= go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= @@ -1988,19 +1037,16 @@ go.opentelemetry.io/collector/extension v0.102.1 h1:gAvE3w15q+Vv0Tj100jzcDpeMTyc go.opentelemetry.io/collector/extension v0.102.1/go.mod h1:XBxUOXjZpwYLZYOK5u3GWlbBTOKmzStY5eU1R/aXkIo= go.opentelemetry.io/collector/extension/auth v0.102.1 h1:GP6oBmpFJjxuVruPb9X40bdf6PNu9779i8anxa+wW6U= go.opentelemetry.io/collector/extension/auth v0.102.1/go.mod h1:U2JWz8AW1QXX2Ap3ofzo5Dn2fZU/Lglld97Vbh8BZS0= -go.opentelemetry.io/collector/featuregate v1.5.0/go.mod h1:w7nUODKxEi3FLf1HslCiE6YWtMtOOrMnSwsDam8Mg9w= go.opentelemetry.io/collector/featuregate v1.9.0 h1:mC4/HnR5cx/kkG1RKOQAvHxxg5Ktmd9gpFdttPEXQtA= go.opentelemetry.io/collector/featuregate v1.9.0/go.mod h1:PsOINaGgTiFc+Tzu2K/X2jP+Ngmlp7YKGV1XrnBkH7U= go.opentelemetry.io/collector/otelcol v0.102.1 h1:JdRG3ven+c5k703QpZG5bxJi4JJOnWaNP/EJvN+oYnI= go.opentelemetry.io/collector/otelcol v0.102.1/go.mod h1:kHf9KBXOLZXajR1On8XJbBBGcgh2I2+/mVVroPzOLJU= -go.opentelemetry.io/collector/pdata v1.5.0/go.mod h1:TYj8aKRWZyT/KuKQXKyqSEvK/GV+slFaDMEI+Ke64Yw= go.opentelemetry.io/collector/processor v0.102.1 h1:79NWs7kTgmgxOIQacuZyDf+mYWuoJZS07SHwZT7sZ4Y= go.opentelemetry.io/collector/processor v0.102.1/go.mod h1:sNM41tEHgv3YA/Dz9/6F8oCeObrqnKCGOMs7wS6Ldus= go.opentelemetry.io/collector/receiver v0.102.1 h1:353t4U3o0RdU007JcQ4sRRzl72GHCJZwXDr8cCOcEbI= go.opentelemetry.io/collector/receiver v0.102.1/go.mod h1:pYjMzUkvUlxJ8xt+VbI1to8HMtVlv8AW/K/2GQQOTB0= go.opentelemetry.io/collector/receiver/otlpreceiver v0.102.1 h1:65/8lkVmOu6gwBw99W+QUQBeDC2qVTwlaiqy7/SpauY= go.opentelemetry.io/collector/receiver/otlpreceiver v0.102.1/go.mod h1:0hmxfFSSqKJjRGvgYjp/XvptbAgLhLguwNgJqMp7zd0= -go.opentelemetry.io/collector/semconv v0.98.0/go.mod h1:8ElcRZ8Cdw5JnvhTOQOdYizkJaQ10Z2fS+R6djOnj6A= go.opentelemetry.io/collector/semconv v0.116.0 h1:63xCZomsKJAWmKGWD3lnORiE3WKW6AO4LjnzcHzGx3Y= go.opentelemetry.io/collector/semconv v0.116.0/go.mod h1:N6XE8Q0JKgBN2fAhkUQtqK9LT7rEGR6+Wu/Rtbal1iI= go.opentelemetry.io/collector/service v0.102.1 h1:Lg7qrC4Zctd/OAlkpdsaZaUY+jLEGLLnOigfBLP2GW8= @@ -2013,22 +1059,16 @@ go.opentelemetry.io/contrib/detectors/gcp v1.32.0 h1:P78qWqkLSShicHmAzfECaTgvslq go.opentelemetry.io/contrib/detectors/gcp v1.32.0/go.mod h1:TVqo0Sda4Cv8gCIixd7LuLwW4EylumVWfhjZJjDD4DU= go.opentelemetry.io/contrib/exporters/autoexport v0.53.0 h1:13K+tY7E8GJInkrvRiPAhC0gi/7vKjzDNhtmCf+QXG8= go.opentelemetry.io/contrib/exporters/autoexport v0.53.0/go.mod h1:lyQF6xQ4iDnMg4sccNdFs1zf62xd79YI8vZqKjOTwMs= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0/go.mod h1:r9vWsPS/3AQItv3OSlEJ/E4mbrhUbbw18meOjArPtKQ= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0/go.mod h1:DKdbWcT4GH1D0Y3Sqt/PFXt2naRKDWtU+eE6oLdFNA8= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0/go.mod h1:HDBUsEjOuRC0EzKZ1bSaRGZWUBAzo+MhAcUUORSr4D0= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.58.0/go.mod h1:uosvgpqTcTXtcPQORTbEkZNDQTCDOgTz1fe6aLSyqrQ= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q= go.opentelemetry.io/contrib/propagators/b3 v1.27.0 h1:IjgxbomVrV9za6bRi8fWCNXENs0co37SZedQilP2hm0= go.opentelemetry.io/contrib/propagators/b3 v1.27.0/go.mod h1:Dv9obQz25lCisDvvs4dy28UPh974CxkahRDUPsY7y9E= -go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= -go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= -go.opentelemetry.io/otel v1.23.0/go.mod h1:YCycw9ZeKhcJFrb34iVSkyT0iczq/zYDtZYFufObyB0= +go.opentelemetry.io/contrib/propagators/jaeger v1.33.0/go.mod h1:ku/EpGk44S5lyVMbtJRK2KFOnXEehxf6SDnhu1eZmjA= +go.opentelemetry.io/contrib/samplers/jaegerremote v0.27.0/go.mod h1:IohbtCIY5Erb6wKnDddXOMNlG7GwyZnkrgcqjPmhpaA= go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel v1.25.0/go.mod h1:Wa2ds5NOXEMkCmUou1WA7ZBfLTHWIsp034OVD7AO+Vg= go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= go.opentelemetry.io/otel/bridge/opencensus v1.27.0 h1:ao9aGGHd+G4YfjBpGs6vbkvt5hoC67STlJA9fCnOAcs= @@ -2039,11 +1079,8 @@ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 h1:U2g go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0/go.mod h1:yeGZANgEcpdx/WK0IvvRFC+2oLiMS2u4L/0Rj2M2Qr0= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.28.0 h1:aLmmtjRke7LPDQ3lvpFz+kNEH43faFhzW7v8BFIEydg= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.28.0/go.mod h1:TC1pyCt6G9Sjb4bQpShH+P5R53pO6ZuGnHuuln9xMeE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.25.0/go.mod h1:h95q0LBGh7hlAC08X2DhSeyIG02YQ0UyioTCVAqRPmc= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.25.0/go.mod h1:8GlBGcDk8KKi7n+2S4BT/CPZQYH3erLu0/k64r1MYgo= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.25.0/go.mod h1:e7ciERRhZaOZXVjx5MiL8TK5+Xv7G5Gv5PA2ZDEJdL8= go.opentelemetry.io/otel/exporters/prometheus v0.50.0 h1:2Ewsda6hejmbhGFyUvWZjUThC98Cf8Zy6g0zkIimOng= go.opentelemetry.io/otel/exporters/prometheus v0.50.0/go.mod h1:pMm5PkUo5YwbLiuEf7t2xg4wbP0/eSJrMxIMxKosynY= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.4.0 h1:0MH3f8lZrflbUWXVxyBg/zviDFdGE062uKh5+fu8Vv0= @@ -2052,66 +1089,30 @@ go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.28.0 h1:BJee2iLkfRfl9l go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.28.0/go.mod h1:DIzlHs3DRscCIBU3Y9YSzPfScwnYnzfnCd4g8zA7bZc= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.28.0 h1:EVSnY9JbEEW92bEkIYOVMw4q1WJxIAGoFTrtYOzWuRQ= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.28.0/go.mod h1:Ea1N1QQryNXpCD0I1fdLibBAIpQuBkznMmkdKrapk1Y= -go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= -go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY= -go.opentelemetry.io/otel/metric v1.23.0/go.mod h1:MqUW2X2a6Q8RN96E2/nqNoT+z9BSms20Jb7Bbp+HiTo= go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/metric v1.25.0/go.mod h1:rkDLUSd2lC5lq2dFNrX9LGAbINP5B7WBkC78RXCpH5s= go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= -go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/sdk v1.25.0/go.mod h1:oFgzCM2zdsxKzz6zwpTZYLLQsFwc+K0daArPdIhuxkw= go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= -go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= -go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= -go.opentelemetry.io/otel/trace v1.23.0/go.mod h1:GSGTbIClEsuZrGIzoEHqsVfxgn5UkggkflQwDScNUsk= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= -go.opentelemetry.io/otel/trace v1.25.0/go.mod h1:hCCs70XM/ljO+BeQkyFnbK28SBIJ/Emuha+ccrCRT7I= go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= -go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= -go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210915214749-c084706c2272/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/exp v0.0.0-20220328175248-053ad81199eb/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= -golang.org/x/exp v0.0.0-20230206171751-46f607a40771/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= -golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= -golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= -golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= -golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e h1:qyrTQ++p1afMkO4DPEeLGq/3oTsdlvdH4vqZUBWzUKM= @@ -2120,36 +1121,13 @@ golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4= golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs= -golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= -golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= -golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= -golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= -golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= @@ -2157,35 +1135,12 @@ golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= -golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= -golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= -golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= -golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= -golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= -golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= -golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= -golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= @@ -2193,190 +1148,42 @@ golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/telemetry v0.0.0-20240208230135-b75ee8823808/go.mod h1:KG1lNk5ZFNssSZLrpVb4sMXKMpGwGXOxSG3rnu2gZQQ= -golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457 h1:zf5N6UOrA487eEFacMePxjXAJctxKmyjKUsjA11Uzuk= golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= -golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= -golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= -golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= -golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= -golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= -golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= -golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= -golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= -golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= -golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= -golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= -golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= -golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= -golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= -golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= -golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= -golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= +golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= -gonum.org/v1/gonum v0.12.0/go.mod h1:73TDxJfAAHeA8Mk9mf8NlIppyhQNo5GLTcYeqgo2lvY= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc= gonum.org/v1/plot v0.14.0 h1:+LBDVFYwFe4LHhdP8coW6296MBEY4nQ+Y4vuUpJopcE= gonum.org/v1/plot v0.14.0/go.mod h1:MLdR9424SJed+5VqC6MsouEpig9pZX2VZ57H9ko2bXU= -google.golang.org/api v0.125.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= -google.golang.org/api v0.128.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWLY750= -google.golang.org/api v0.139.0/go.mod h1:CVagp6Eekz9CjGZ718Z+sloknzkDJE7Vc1Ckj9+viBk= -google.golang.org/api v0.149.0/go.mod h1:Mwn1B7JTXrzXtnvmzQE2BD6bYZQ8DShKZDZbeN9I7qI= -google.golang.org/api v0.150.0/go.mod h1:ccy+MJ6nrYFgE3WgRx/AMXOxOmU8Q4hSa+jjibzhxcg= -google.golang.org/api v0.155.0/go.mod h1:GI5qK5f40kCpHfPn6+YzGAByIKWv8ujFnmoWm7Igduk= -google.golang.org/api v0.157.0/go.mod h1:+z4v4ufbZ1WEpld6yMGHyggs+PmAHiaLNj5ytP3N01g= -google.golang.org/api v0.160.0/go.mod h1:0mu0TpK33qnydLvWqbImq2b1eQ5FHRSDCBzAxX9ZHyw= -google.golang.org/api v0.162.0/go.mod h1:6SulDkfoBIg4NFmCuZ39XeeAgSHCPecfSUuDyYlAHs0= -google.golang.org/api v0.164.0/go.mod h1:2OatzO7ZDQsoS7IFf3rvsE17/TldiU3F/zxFHeqUB5o= -google.golang.org/api v0.169.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg= -google.golang.org/api v0.174.0/go.mod h1:aC7tB6j0HR1Nl0ni5ghpx6iLasmAX78Zkh/wgxAAjLg= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= -google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk= -google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk= -google.golang.org/genproto v0.0.0-20230629202037-9506855d4529/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= -google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:O9kGHb51iE/nOGvQaDUuadVYqovW56s5emA88lQnj6Y= -google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0= -google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:0ggbjUrZYpy1q+ANUS30SEoGZ53cdfwtbuG7Ptgy108= -google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8= -google.golang.org/genproto v0.0.0-20230821184602-ccc8af3d0e93/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:CCviP9RmpZ1mxVr8MUjCnSiY09IbAXZxhLE6EhHIdPU= -google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk= -google.golang.org/genproto v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:EMfReVxb80Dq1hhioy0sOsY9jCE46YDgHlJ7fWVUWRE= -google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI= -google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405/go.mod h1:3WDQMjmJk36UQhjQ89emUzb1mdaHcPeeAh4SCBKznB4= -google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY= -google.golang.org/genproto v0.0.0-20231120223509-83a465c0220f/go.mod h1:nWSwAFPb+qfNJXsoeO3Io7zf4tMSfN8EA8RlDA04GhY= -google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3/go.mod h1:5RBcpGRxr25RbDzY5w+dmaqpSEvl8Gwl1x2CICf60ic= -google.golang.org/genproto v0.0.0-20231212172506-995d672761c0/go.mod h1:l/k7rMz0vFTBPy+tFSGvXEd3z+BcoG1k7EHbqm+YBsY= -google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917/go.mod h1:pZqR+glSb11aJ+JQcczCvgf47+duRuzNSKqE8YAQnV0= -google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:+Rvu7ElI+aLzyDQhpHMFMMltsD6m7nqpuWDd2CwJw3k= google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= -google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= -google.golang.org/genproto v0.0.0-20240205150955-31a09d347014/go.mod h1:xEgQu1e4stdSSsxPDK8Azkrk/ECl5HvdPf6nbZrTS5M= -google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= -google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= -google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:mPBs5jNgx2GuQGvFwUvVKqtn6HsUw9nP64BedgvqEsQ= -google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= -google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= -google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5/go.mod h1:5DZzOUPCLYL3mNkQ0ms0F3EuUNZ7py1Bqeq6sxzI7/Q= -google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= -google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= -google.golang.org/genproto/googleapis/api v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:RdyHbowztCGQySiCvQPgWQWgWhGnouTdCflKoDBt32U= -google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97/go.mod h1:iargEX0SFPm3xcfMI0d1domjg0ZF4Aa0p2awqyxhvF0= -google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:SUBoKXbI1Efip18FClrQVGjWcyd0QZd8KkvdP34t7ww= -google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870= -google.golang.org/genproto/googleapis/api v0.0.0-20231030173426-d783a09b4405/go.mod h1:oT32Z4o8Zv2xPQTg0pbVaPr0MPOH6f14RgXt7zfIpwg= -google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= -google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f/go.mod h1:Uy9bTZJqmfrw2rIBxgGLnamc78euZULUBrLZ9XTITKI= -google.golang.org/genproto/googleapis/api v0.0.0-20231211222908-989df2bf70f3/go.mod h1:k2dtGpRrbsSyKcNPKKI5sstZkrNCZwpU/ns96JoHbGg= -google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0/go.mod h1:CAny0tYF+0/9rmDB9fahA9YLzX3+AEVl1qXbv5hhj6c= -google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917/go.mod h1:CmlNWB9lSezaYELKS5Ym1r44VrrbPUa7JTvw+6MbpJ0= -google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:B5xPO//w8qmBDjGReYLpR6UJPnkldGkCSMoH/2vxJeg= -google.golang.org/genproto/googleapis/api v0.0.0-20240122161410-6c6643bf1457/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= -google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= -google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= -google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014/go.mod h1:rbHMSEDyoYX62nRVLOCc4Qt1HbsdytAYoVwgjiOhF3I= -google.golang.org/genproto/googleapis/api v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:PVreiBMirk8ypES6aw9d4p6iiBNSIfZEBqr3UGoAi2E= -google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8= -google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= -google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be/go.mod h1:dvdCTIoAGbkWbcIKBniID56/7XHTt6WfxXNMxuziJ+w= google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117/go.mod h1:OimBR/bc1wPO9iV4NC2bpyjy3VnAwZh5EBPQdtaE5oo= google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo= google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53/go.mod h1:riSXTwQ4+nqmPGtobMFyW5FqVAmIs0St6VPp4Ug7CE4= google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a/go.mod h1:jehYqy3+AhJU9ve55aNOaSml7wUXjF9x6z2LcCfpAhY= google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb/go.mod h1:E5//3O5ZIG2l71Xnt+P/CYUY8Bxs8E7WMoZ9tlcMbAY= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20230807174057-1744710a1577/go.mod h1:NjCQG/D8JandXxM57PZbAJL1DCNL6EypA0vPPwfsc7c= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20231030173426-d783a09b4405/go.mod h1:GRUCuLdzVqZte8+Dl/D4N25yLzcGqqWaYkeVOwulFqw= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20231212172506-995d672761c0/go.mod h1:guYXGPwC6jwxgWKW5Y405fKWOFNwlvUlUnzyp9i0uqo= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:ZSvZ8l+AWJwXw91DoTjWjaVLpWU6o0eZ4YLYpH8aLeQ= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:SCz6T5xjNXM4QFPRwxHcfChp7V+9DcXR3ay2TkHR8Tg= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20240205150955-31a09d347014/go.mod h1:EhZbXt+eY4Yr3YVaEGLdNZF5viWowOJZ8KTPqjYMKzg= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:vh/N7795ftP0AkN1w8XKqN4w1OdUKXW5Eummda+ofv8= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20240325203815-454cdb8f5daa/go.mod h1:IN9OQUXZ0xT+26MDwZL8fJcYw+y99b0eYPA2U15Jt8o= google.golang.org/genproto/googleapis/bytestream v0.0.0-20250102185135-69823020774d h1:NZBSeFsuFS5YrgHMW/8xfTbzNXMshQPNgq2Yb7xipEs= google.golang.org/genproto/googleapis/bytestream v0.0.0-20250102185135-69823020774d/go.mod h1:s4mHJ3FfG8P6A3O+gZ8TVqB3ufjOl9UG3ANCMMwCHmo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230629202037-9506855d4529/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:8mL13HKkDa+IuJ8yruA3ci0q+0vsUz4m//+ottjwS5o= google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230731190214-cbb8c96f2d6d/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5/go.mod h1:zBEcrKX2ZOcEkHWxBPAIvYUWOKKMIhYcmNiUIu2ji3I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230920183334-c177e329c48b/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:KSqppvjFjtoCI+KGd4PELB0qLNxdJHRGqRI09mB6pQA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97/go.mod h1:v7nGkzlmW8P3n/bKmWBn2WpBjpOEx8Q6gMueudAmKfY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405/go.mod h1:67X1fPuzjcrkymZzZV1vvkFeTn2Rvc6lYF9MYFGCcwE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231211222908-989df2bf70f3/go.mod h1:eJVxU6o+4G1PSczBr85xmyvSNYAKvAYgkub40YGomFM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0/go.mod h1:FUoWkonphQm3RhTS+kOEhF8h0iDpm4tdXolVCeZ9KKA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917/go.mod h1:xtjpI3tXFPP051KaWnhvxkiubL/6dJ18vLVf7q2pTOU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240122161410-6c6643bf1457/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014/go.mod h1:SaPjaZGWb0lPqs6Ittu0spdfrOArqji4ZdeP5IC/9N4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:YUWgXUFRPfoYK1IHMuxH5K6nPEXSCzIMljnQ59lLRCk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240228201840-1f18d85a4ec2/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240311132316-a219d84964c2/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240415141817-7cd4c1c1f9ec/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA= google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4= -google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= -google.golang.org/grpc v1.56.1/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= -google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= -google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= -google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= -google.golang.org/grpc v1.60.0/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= -google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= -google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= -google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= -google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= -google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= -google.golang.org/grpc v1.63.0/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= -google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= @@ -2390,81 +1197,35 @@ google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojt gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= -gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= -gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0 h1:CuXP0Pjfw9rOuY6EP+UvtNvt5DSqHpIxILZKT/quCZI= gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg= gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= gopkg.in/telebot.v3 v3.2.1 h1:3I4LohaAyJBiivGmkfB+CiVu7QFOWkuZ4+KHgO/G3rs= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= -gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= honnef.co/go/tools v0.3.2 h1:ytYb4rOqyp1TSa2EPvNVwtPQJctSELKaMyLfqNP4+34= honnef.co/go/tools v0.3.2/go.mod h1:jzwdWgg7Jdq75wlfblQxO4neNaFFSvgc1tD5Wv8U0Yw= howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= -k8s.io/api v0.29.3/go.mod h1:y2yg2NTyHUUkIoTC+phinTnEa3KFM6RZ3szxt014a80= -k8s.io/apimachinery v0.29.3/go.mod h1:hx/S4V2PNW4OMg3WizRrHutyB5la0iCUbZym+W0EQIU= -k8s.io/client-go v0.29.3/go.mod h1:tkDisCvgPfiRpxGnOORfkljmS+UrW+WtXAy2fTvXJB0= k8s.io/code-generator v0.32.1 h1:4lw1kFNDuFYXquTkB7Sl5EwPMUP2yyW9hh6BnFfRZFY= k8s.io/code-generator v0.32.1/go.mod h1:zaILfm00CVyP/6/pJMJ3zxRepXkxyDfUV5SNG4CjZI4= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6 h1:4s3/R4+OYYYUKptXPhZKjQ04WJ6EhQQVFdjOFvCazDk= -k8s.io/gengo v0.0.0-20230829151522-9cce18d56c01/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= -k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70/go.mod h1:VH3AT8AaQOqiGjMF9p0/IM1Dj+82ZwjfxUP1IxaHE+8= k8s.io/gengo/v2 v2.0.0-20240911193312-2b36238f13e9 h1:si3PfKm8dDYxgfbeA6orqrtLkvvIeH8UqffFJDl0bz4= k8s.io/gengo/v2 v2.0.0-20240911193312-2b36238f13e9/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= -k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= -k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= -k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= -k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= -lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= modernc.org/cc/v3 v3.36.3 h1:uISP3F66UlixxWEcKuIWERa4TwrZENHSL8tWxZz8bHg= -modernc.org/cc/v3 v3.37.0/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20= -modernc.org/cc/v3 v3.38.1/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20= -modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= -modernc.org/ccgo/v3 v3.0.0-20220904174949-82d86e1b6d56/go.mod h1:YSXjPL62P2AMSxBphRHPn7IkzhVHqkvOnRKAKh+W6ZI= -modernc.org/ccgo/v3 v3.0.0-20220910160915-348f15de615a/go.mod h1:8p47QxPkdugex9J4n9P2tLZ9bK01yngIVp00g4nomW0= modernc.org/ccgo/v3 v3.16.9 h1:AXquSwg7GuMk11pIdw7fmO1Y/ybgazVkMhsZWCV0mHM= -modernc.org/ccgo/v3 v3.16.13-0.20221017192402-261537637ce8/go.mod h1:fUB3Vn0nVPReA+7IG7yZDfjv1TMWjhQP8gCxrFAtL5g= -modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk= modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= -modernc.org/libc v1.17.4/go.mod h1:WNg2ZH56rDEwdropAJeZPQkXmDwh+JCA1s/htl6r2fA= -modernc.org/libc v1.18.0/go.mod h1:vj6zehR5bfc98ipowQOM2nIDUZnVew/wNC/2tOGS+q0= -modernc.org/libc v1.19.0/go.mod h1:ZRfIaEkgrYgZDl6pa4W39HgN5G/yDW+NRmNKZBDFrk0= -modernc.org/libc v1.20.3/go.mod h1:ZRfIaEkgrYgZDl6pa4W39HgN5G/yDW+NRmNKZBDFrk0= -modernc.org/libc v1.21.2/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI= -modernc.org/libc v1.21.4/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI= -modernc.org/libc v1.22.2/go.mod h1:uvQavJ1pZ0hIoC/jfqNoMLURIMhKzINIWypNM17puug= -modernc.org/libc v1.22.4/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY= -modernc.org/memory v1.3.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/sqlite v1.18.2/go.mod h1:kvrTLEWgxUcHa2GfHBQtanR1H9ht3hTJNtKpzH9k1u0= -modernc.org/sqlite v1.21.2/go.mod h1:cxbLkB5WS32DnQqeH4h4o1B0eMr8W/y8/RGuxQ3JsC0= modernc.org/tcl v1.13.1 h1:npxzTwFTZYM8ghWicVIX1cRWzj7Nd8i6AqqX2p+IYao= -modernc.org/tcl v1.13.2/go.mod h1:7CLiGIPo1M8Rv1Mitpv5akc2+8fxUd2y2UzC/MfMzy0= -modernc.org/tcl v1.15.1/go.mod h1:aEjeGJX2gz1oWKOLDVZ2tnEWLUrIn8H+GFu+akoDhqs= -modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/z v1.5.1 h1:RTNHdsrOpeoSeOF4FbzTo8gBYByaJ5xT7NgZ9ZqRiJM= -modernc.org/z v1.7.0/go.mod h1:hVdgNMh8ggTuRG1rGU8x+xGRFfiQUIAw0ZqlPy8+HyQ= rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE= rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4= rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY= rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e h1:4Z09Hglb792X0kfOBBJUPFEyvVfQWrYT/l8h5EKA6JQ= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/packages/grafana-data/src/transformations/transformers/histogram.test.ts b/packages/grafana-data/src/transformations/transformers/histogram.test.ts index 7bbd03397a0..f8aa3f9c991 100644 --- a/packages/grafana-data/src/transformations/transformers/histogram.test.ts +++ b/packages/grafana-data/src/transformations/transformers/histogram.test.ts @@ -1,8 +1,14 @@ import { toDataFrame } from '../../dataframe/processDataFrame'; -import { FieldType } from '../../types/dataFrame'; +import { Field, FieldType } from '../../types/dataFrame'; import { mockTransformationsRegistry } from '../../utils/tests/mockTransformationsRegistry'; -import { histogramTransformer, buildHistogram, histogramFieldsToFrame } from './histogram'; +import { + histogramTransformer, + buildHistogram, + histogramFieldsToFrame, + HistogramFields, + joinHistograms, +} from './histogram'; describe('histogram frames frames', () => { beforeAll(() => { @@ -280,3 +286,110 @@ describe('histogram frames frames', () => { `); }); }); + +describe('joinHistograms', () => { + type TestHistogram = { + xMin: number[]; + xMax: number[]; + counts: number[][]; + }; + + function toField(name: string, values: number[]): Field { + return { + config: {}, + name, + type: FieldType.number, + values, + }; + } + + function testHistogramToHistogram(test: TestHistogram): HistogramFields { + return { + xMin: toField('xMin', test.xMin), + xMax: toField('xMax', test.xMax), + counts: test.counts.map((values) => toField(`count`, values)), + }; + } + + type TestCase = { + name: string; + histograms: TestHistogram[]; + expected: TestHistogram; + }; + + const testCases: TestCase[] = [ + { + name: 'just one histogram', + histograms: [ + { + xMin: [1, 2, 3], + xMax: [2, 3, 4], + counts: [[1, 2, 3]], + }, + ], + expected: { + xMin: [1, 2, 3], + xMax: [2, 3, 4], + counts: [[1, 2, 3]], + }, + }, + { + name: 'two histograms with same bucket sizes', + histograms: [ + { + xMin: [1, 3, 4], + xMax: [2, 4, 5], + counts: [[1, 2, 3]], + }, + { + xMin: [1, 3, 4], + xMax: [2, 4, 5], + counts: [[4, 5, 6]], + }, + ], + expected: { + xMin: [1, 3, 4], + xMax: [2, 4, 5], + counts: [ + [1, 2, 3], + [4, 5, 6], + ], + }, + }, + { + name: 'two histograms with same bucket sizes but counts in some different buckets', + histograms: [ + { + xMin: [1, 3, 4], + xMax: [2, 4, 5], + counts: [[1, 2, 3]], + }, + { + xMin: [2, 3, 6], + xMax: [3, 4, 7], + counts: [[4, 5, 6]], + }, + ], + expected: { + xMin: [1, 2, 3, 4, 6], + xMax: [2, 3, 4, 5, 7], + counts: [ + [1, 0, 2, 3, 0], + [0, 4, 5, 0, 6], + ], + }, + }, + ]; + + testCases.forEach((tc) => { + it(tc.name, () => { + const result = joinHistograms(tc.histograms.map(testHistogramToHistogram)); + + expect({ + xMin: result.xMin.values, + xMax: result.xMax.values, + counts: result.counts.map((f) => f.values), + }).toEqual(tc.expected); + }); + }); +}); diff --git a/packages/grafana-data/src/transformations/transformers/histogram.ts b/packages/grafana-data/src/transformations/transformers/histogram.ts index 7e5def97a2f..8fa69f64a40 100644 --- a/packages/grafana-data/src/transformations/transformers/histogram.ts +++ b/packages/grafana-data/src/transformations/transformers/histogram.ts @@ -1,5 +1,6 @@ import { map } from 'rxjs/operators'; +import { outerJoinDataFrames } from '../..'; import { getDisplayProcessor } from '../../field/displayProcessor'; import { createTheme } from '../../themes/createTheme'; import { GrafanaTheme2 } from '../../themes/types'; @@ -325,7 +326,11 @@ export function getHistogramFields(frame: DataFrame): HistogramFields | undefine /** * @alpha */ -export function buildHistogram(frames: DataFrame[], options?: HistogramTransformerOptions): HistogramFields | null { +export function buildHistogram( + frames: DataFrame[], + options?: HistogramTransformerOptions, + theme?: GrafanaTheme2 +): HistogramFields | null { let bucketSize = options?.bucketSize; let bucketCount = options?.bucketCount ?? DEFAULT_BUCKET_COUNT; let bucketOffset = options?.bucketOffset ?? 0; @@ -412,13 +417,20 @@ export function buildHistogram(frames: DataFrame[], options?: HistogramTransform if (field.type === FieldType.number) { let fieldHist = histogram(field.values, getBucket, histFilter, histSort); histograms.push(fieldHist); - counts.push({ + + const count = { ...field, config: { ...field.config, unit: field.config.unit === 'short' ? 'short' : undefined, }, + }; + + count.display = getDisplayProcessor({ + field: count, + theme: theme ?? createTheme(), }); + counts.push(count); if (!config && field.config.unit) { config = field.config; } @@ -573,12 +585,6 @@ export function histogramFieldsToFrame(info: HistogramFields, theme?: GrafanaThe info.xMax.display = display; } - // ensure updated units are reflected on the count field used for y axis formatting - info.counts[0].display = getDisplayProcessor({ - field: info.counts[0], - theme: theme ?? createTheme(), - }); - return { length: info.xMin.values.length, meta: { @@ -588,3 +594,63 @@ export function histogramFieldsToFrame(info: HistogramFields, theme?: GrafanaThe refId: `${DataTransformerID.histogram}`, }; } + +/** + * + * Join multiple histograms into a histogram with multiple counts. + * Useful eg if you want to overlay them for comparison. + * + * This is needed because histogram results from database + * will have buckets omitted for 0 counts, but when joining multiple histograms + * we need to fill in the 0 values for missing buckets. + * + * Returns field configs of the first provided histogram. + * @alpha + */ + +export function joinHistograms(histograms: HistogramFields[]): HistogramFields { + if (histograms.length === 1) { + return histograms[0]; + } + + let joined = outerJoinDataFrames({ + frames: histograms.map((h) => ({ + length: h.xMax.values.length, + fields: [h.xMax, h.xMin, ...h.counts], + })), + joinBy: (field) => field.name === 'xMax', + })!; + + let xMaxField: Field | null = null; + let xMinField: Field | null = null; + let countFields: Field[] = []; + + // merge all xMin fields into first xMin field + // and default all count fields to 0 + joined.fields.forEach((f) => { + if (f.name === 'xMax') { + xMaxField = f; + } else if (f.name === 'xMin') { + if (xMinField == null) { + xMinField = f; + } else { + for (let i = 0; i < f.values.length; i++) { + xMinField.values[i] ??= f.values[i]; + } + } + } else { + countFields.push({ + ...f, + values: f.values.map((v) => v ?? 0), + }); + } + }); + + const result: HistogramFields = { + xMin: xMinField!, + xMax: xMaxField!, + counts: countFields, + }; + + return result; +} diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts index 84091bf6c14..cda45576882 100644 --- a/packages/grafana-data/src/types/featureToggles.gen.ts +++ b/packages/grafana-data/src/types/featureToggles.gen.ts @@ -256,4 +256,5 @@ export interface FeatureToggles { alertingJiraIntegration?: boolean; alertingRuleVersionHistoryRestore?: boolean; newShareReportDrawer?: boolean; + rendererDisableAppPluginsPreload?: boolean; } diff --git a/packages/grafana-prometheus/src/querybuilder/components/MetricCombobox.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/MetricCombobox.test.tsx index c9ff1d55cd2..c832a547bdc 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/MetricCombobox.test.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/MetricCombobox.test.tsx @@ -35,9 +35,13 @@ describe('MetricCombobox', () => { } as unknown as DataSourceInstanceSettings; const mockDatasource = new PrometheusDatasource(instanceSettings); - const mockValues = [{ label: 'random_metric' }, { label: 'unique_metric' }, { label: 'more_unique_metric' }]; - // Mock metricFindQuery which will call backend API + // Options returned when user first opens the combobox - returned by onGetMetrics + const initialMockValues = [{ label: 'top_metric_one' }, { label: 'top_metric_two' }, { label: 'top_metric_three' }]; + const mockOnGetMetrics = jest.fn(() => Promise.resolve(initialMockValues.map((v) => ({ value: v.label })))); + + // Options returned when user searches for a metric + const mockValues = [{ label: 'random_metric' }, { label: 'unique_metric' }, { label: 'more_unique_metric' }]; mockDatasource.metricFindQuery = jest.fn((query: string) => { // return Promise.resolve([]); // Use the label values regex to get the values inside the label_values function call @@ -61,7 +65,6 @@ describe('MetricCombobox', () => { }); const mockOnChange = jest.fn(); - const mockOnGetMetrics = jest.fn(() => Promise.resolve(mockValues.map((v) => ({ value: v.label })))); const defaultProps: MetricComboboxProps = { metricLookupDisabled: false, @@ -92,10 +95,11 @@ describe('MetricCombobox', () => { const combobox = screen.getByPlaceholderText('Select metric'); await userEvent.click(combobox); - expect(mockOnGetMetrics).toHaveBeenCalledTimes(1); - - const item = await screen.findByRole('option', { name: 'random_metric' }); + const item = await screen.findByRole('option', { name: 'top_metric_one' }); expect(item).toBeInTheDocument(); + + // This should be asserted by the above check, but double check anyway + expect(mockOnGetMetrics).toHaveBeenCalledTimes(1); }); it('fetches metrics for the users query', async () => { @@ -108,8 +112,9 @@ describe('MetricCombobox', () => { const item = await screen.findByRole('option', { name: 'unique_metric' }); expect(item).toBeInTheDocument(); - const negativeItem = screen.queryByRole('option', { name: 'random_metric' }); - expect(negativeItem).not.toBeInTheDocument(); + // This should be asserted by the above check, but double check anyway + // This is the actual argument, created by formatKeyValueStringsForLabelValuesQuery() + expect(mockDatasource.metricFindQuery).toHaveBeenCalledWith('label_values({__name__=~".*unique.*"},__name__)'); }); it('calls onChange with the correct value when a metric is selected', async () => { @@ -118,10 +123,10 @@ describe('MetricCombobox', () => { const combobox = screen.getByPlaceholderText('Select metric'); await userEvent.click(combobox); - const item = await screen.findByRole('option', { name: 'random_metric' }); + const item = await screen.findByRole('option', { name: 'top_metric_two' }); await userEvent.click(item); - expect(mockOnChange).toHaveBeenCalledWith({ metric: 'random_metric', labels: [], operations: [] }); + expect(mockOnChange).toHaveBeenCalledWith({ metric: 'top_metric_two', labels: [], operations: [] }); }); it('shows the metrics explorer button by default', () => { diff --git a/packages/grafana-ui/src/components/Combobox/Combobox.test.tsx b/packages/grafana-ui/src/components/Combobox/Combobox.test.tsx index 6127c007e56..e54c94d1977 100644 --- a/packages/grafana-ui/src/components/Combobox/Combobox.test.tsx +++ b/packages/grafana-ui/src/components/Combobox/Combobox.test.tsx @@ -1,4 +1,4 @@ -import { act, render, screen, fireEvent } from '@testing-library/react'; +import { act, render, screen, fireEvent, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; @@ -395,7 +395,9 @@ describe('Combobox', () => { const input = screen.getByRole('combobox'); await user.click(input); - expect(asyncSpy).toHaveBeenCalledTimes(1); // Called on open + expect(asyncSpy).not.toHaveBeenCalledTimes(1); // Not called yet + act(() => jest.advanceTimersByTime(200)); // Add the debounce time + expect(asyncSpy).toHaveBeenCalledTimes(1); // Then check if called on open asyncSpy.mockClear(); await user.keyboard('a'); @@ -434,9 +436,9 @@ describe('Combobox', () => { }); it('should display message when there is an error loading async options', async () => { - const asyncOptions = jest.fn(() => { - throw new Error('Could not retrieve options'); - }); + const fetchData = jest.fn(); + const asyncOptions = fetchData.mockRejectedValue(new Error('Could not retrieve options')); + const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(); render(); @@ -445,12 +447,15 @@ describe('Combobox', () => { await user.type(input, 'test'); await act(async () => { - jest.advanceTimersToNextTimer(); + jest.advanceTimersByTimeAsync(500); }); + expect(asyncOptions).rejects.toThrow('Could not retrieve options'); + await waitFor(() => expect(consoleErrorSpy).toHaveBeenCalled()); const emptyMessage = screen.queryByText('An error occurred while loading options.'); - expect(emptyMessage).toBeInTheDocument(); + + asyncOptions.mockClear(); }); describe('with a value already selected', () => { diff --git a/packages/grafana-ui/src/components/Combobox/Combobox.tsx b/packages/grafana-ui/src/components/Combobox/Combobox.tsx index f69d15b3038..2a1ea6ae28c 100644 --- a/packages/grafana-ui/src/components/Combobox/Combobox.tsx +++ b/packages/grafana-ui/src/components/Combobox/Combobox.tsx @@ -1,11 +1,9 @@ import { cx } from '@emotion/css'; import { useVirtualizer } from '@tanstack/react-virtual'; import { useCombobox } from 'downshift'; -import { debounce } from 'lodash'; -import { useCallback, useId, useMemo, useState } from 'react'; +import { useId, useMemo } from 'react'; import { useStyles2 } from '../../themes'; -import { logOptions } from '../../utils'; import { t } from '../../utils/i18n'; import { Icon } from '../Icon/Icon'; import { AutoSizeInput } from '../Input/AutoSizeInput'; @@ -14,11 +12,11 @@ import { Portal } from '../Portal/Portal'; import { ScrollContainer } from '../ScrollContainer/ScrollContainer'; import { AsyncError, NotFoundError } from './MessageRows'; -import { fuzzyFind, itemToString } from './filter'; +import { itemToString } from './filter'; import { getComboboxStyles, MENU_OPTION_HEIGHT, MENU_OPTION_HEIGHT_DESCRIPTION } from './getComboboxStyles'; import { ComboboxOption } from './types'; import { useComboboxFloat } from './useComboboxFloat'; -import { StaleResultError, useLatestAsyncCall } from './useLatestAsyncCall'; +import { useOptions } from './useOptions'; // TODO: It would be great if ComboboxOption["label"] was more generic so that if consumers do pass it in (for async), // then the onChange handler emits ComboboxOption with the label as non-undefined. @@ -64,8 +62,6 @@ export interface ComboboxBaseProps onBlur?: () => void; } -const RECOMMENDED_ITEMS_AMOUNT = 100_000; - type ClearableConditionals = | { /** @@ -102,7 +98,6 @@ export type ComboboxProps = ComboboxBaseProps & ClearableConditionals; const noop = () => {}; -const asyncNoop = () => Promise.resolve([]); export const VIRTUAL_OVERSCAN_ITEMS = 4; @@ -113,7 +108,7 @@ export const VIRTUAL_OVERSCAN_ITEMS = 4; */ export const Combobox = (props: ComboboxProps) => { const { - options, + options: allOptions, onChange, value: valueProp, placeholder: placeholderProp, @@ -135,45 +130,13 @@ export const Combobox = (props: ComboboxProps) => // get a consistent Value from it const value = typeof valueProp === 'object' ? valueProp?.value : valueProp; - const isAsync = typeof options === 'function'; - const loadOptions = useLatestAsyncCall(isAsync ? options : asyncNoop); // loadOptions isn't called at all if not async - const [asyncLoading, setAsyncLoading] = useState(false); - const [asyncError, setAsyncError] = useState(false); - - // A custom setter to always prepend the custom value at the beginning, if needed - const [items, baseSetItems] = useState(isAsync ? [] : options); - const setItems = useCallback( - (items: Array>, inputValue: string | undefined) => { - let itemsToSet = items; - logOptions(itemsToSet.length, RECOMMENDED_ITEMS_AMOUNT, id, ariaLabelledBy); - if (inputValue && createCustomValue) { - //Since the label of a normal option does not have to match its value and a custom option has the same value and label, - //we just focus on the value to check if the option already exists - const optionMatchingInput = items.find((opt) => opt.value === inputValue); - - if (!optionMatchingInput) { - const customValueOption = { - label: inputValue, - // Type casting needed to make this work when T is a number - value: inputValue as T, - description: t('combobox.custom-value.description', 'Use custom value'), - }; - - itemsToSet = items.slice(0); - itemsToSet.unshift(customValueOption); - } - } - - baseSetItems(itemsToSet); - }, - [createCustomValue, id, ariaLabelledBy] - ); - - // Memoize for using in fuzzy search - const stringifiedItems = useMemo( - () => (isAsync ? [] : options.map((item) => itemToString(item))), - [options, isAsync] - ); + const { + options: filteredOptions, + updateOptions, + asyncLoading, + asyncError, + } = useOptions(props.options, createCustomValue); + const isAsync = typeof allOptions === 'function'; const selectedItemIndex = useMemo(() => { if (isAsync) { @@ -184,13 +147,13 @@ export const Combobox = (props: ComboboxProps) => return null; } - const index = options.findIndex((option) => option.value === value); + const index = allOptions.findIndex((option) => option.value === value); if (index === -1) { return null; } return index; - }, [valueProp, options, value, isAsync]); + }, [valueProp, allOptions, value, isAsync]); const selectedItem = useMemo(() => { if (valueProp === undefined || valueProp === null) { @@ -198,11 +161,11 @@ export const Combobox = (props: ComboboxProps) => } if (selectedItemIndex !== null && !isAsync) { - return options[selectedItemIndex]; + return allOptions[selectedItemIndex]; } return typeof valueProp === 'object' ? valueProp : { value: valueProp, label: valueProp.toString() }; - }, [selectedItemIndex, isAsync, valueProp, options]); + }, [selectedItemIndex, isAsync, valueProp, allOptions]); const menuId = `downshift-${useId().replace(/:/g, '--')}-menu`; const labelId = `downshift-${useId().replace(/:/g, '--')}-label`; @@ -210,33 +173,15 @@ export const Combobox = (props: ComboboxProps) => const styles = useStyles2(getComboboxStyles); const virtualizerOptions = { - count: items.length, + count: filteredOptions.length, getScrollElement: () => scrollRef.current, - estimateSize: (index: number) => (items[index].description ? MENU_OPTION_HEIGHT_DESCRIPTION : MENU_OPTION_HEIGHT), + estimateSize: (index: number) => + filteredOptions[index].description ? MENU_OPTION_HEIGHT_DESCRIPTION : MENU_OPTION_HEIGHT, overscan: VIRTUAL_OVERSCAN_ITEMS, }; const rowVirtualizer = useVirtualizer(virtualizerOptions); - const debounceAsync = useMemo( - () => - debounce((inputValue: string) => { - loadOptions(inputValue) - .then((opts) => { - setItems(opts, inputValue); - setAsyncLoading(false); - setAsyncError(false); - }) - .catch((err) => { - if (!(err instanceof StaleResultError)) { - setAsyncError(true); - setAsyncLoading(false); - } - }); - }, 200), - [loadOptions, setItems] - ); - const { isOpen, highlightedIndex, @@ -250,7 +195,7 @@ export const Combobox = (props: ComboboxProps) => menuId, labelId, inputId: id, - items, + items: filteredOptions, itemToString, selectedItem, @@ -267,48 +212,9 @@ export const Combobox = (props: ComboboxProps) => scrollIntoView: () => {}, - onInputValueChange: ({ inputValue, isOpen }) => { - if (!isOpen) { - // Prevent stale options from showing on reopen - if (isAsync) { - setItems([], ''); - } - - // Otherwise there's nothing else to do when the menu isnt open - return; - } - - if (!isAsync) { - const filteredItems = fuzzyFind(options, stringifiedItems, inputValue); - setItems(filteredItems, inputValue); - } else { - if (inputValue && createCustomValue) { - setItems([], inputValue); - } - - setAsyncLoading(true); - debounceAsync(inputValue); - } - }, - onIsOpenChange: ({ isOpen, inputValue }) => { - // Loading async options mostly happens in onInputValueChange, but if the menu is opened with an empty input - // then onInputValueChange isn't called (because the input value hasn't changed) - if (isAsync && isOpen && inputValue === '') { - setAsyncLoading(true); - // TODO: dedupe this loading logic with debounceAsync - loadOptions(inputValue) - .then((opts) => { - setItems(opts, inputValue); - setAsyncLoading(false); - setAsyncError(false); - }) - .catch((err) => { - if (!(err instanceof StaleResultError)) { - setAsyncError(true); - setAsyncLoading(false); - } - }); + if (isOpen && inputValue === '') { + updateOptions(inputValue); } }, @@ -317,7 +223,16 @@ export const Combobox = (props: ComboboxProps) => rowVirtualizer.scrollToIndex(highlightedIndex); } }, + onStateChange: ({ inputValue: newInputValue, type, selectedItem: newSelectedItem }) => { + switch (type) { + case useCombobox.stateChangeTypes.InputChange: + updateOptions(newInputValue ?? ''); + break; + default: + break; + } + }, stateReducer(state, actionAndChanges) { let { changes } = actionAndChanges; const menuBeingOpened = state.isOpen === false && changes.isOpen === true; @@ -353,7 +268,7 @@ export const Combobox = (props: ComboboxProps) => }, }); - const { inputRef, floatingRef, floatStyles, scrollRef } = useComboboxFloat(items, isOpen); + const { inputRef, floatingRef, floatStyles, scrollRef } = useComboboxFloat(filteredOptions, isOpen); const isAutoSize = width === 'auto'; @@ -429,14 +344,16 @@ export const Combobox = (props: ComboboxProps) => {!asyncError && (
    {rowVirtualizer.getVirtualItems().map((virtualRow) => { + const item = filteredOptions[virtualRow.index]; + return (
  • (props: ComboboxProps) => transform: `translateY(${virtualRow.start}px)`, }} {...getItemProps({ - item: items[virtualRow.index], + item: item, index: virtualRow.index, })} >
    - - {items[virtualRow.index].label ?? items[virtualRow.index].value} - - {items[virtualRow.index].description && ( - {items[virtualRow.index].description} - )} + {item.label ?? item.value} + {item.description && {item.description}}
  • ); @@ -463,7 +376,7 @@ export const Combobox = (props: ComboboxProps) => )}
    {asyncError && } - {items.length === 0 && !asyncError && } + {filteredOptions.length === 0 && !asyncError && }
    )} diff --git a/packages/grafana-ui/src/components/Combobox/useOptions.ts b/packages/grafana-ui/src/components/Combobox/useOptions.ts index fc2747cee1e..fffad1613cb 100644 --- a/packages/grafana-ui/src/components/Combobox/useOptions.ts +++ b/packages/grafana-ui/src/components/Combobox/useOptions.ts @@ -3,7 +3,7 @@ import { useState, useCallback, useMemo } from 'react'; import { t } from '../../utils/i18n'; -import { itemFilter } from './filter'; +import { fuzzyFind, itemToString } from './filter'; import { ComboboxOption } from './types'; import { StaleResultError, useLatestAsyncCall } from './useLatestAsyncCall'; @@ -83,14 +83,11 @@ export function useOptions(rawOptions: AsyncOptions { - if (!isAsync) { - setUserTypedSearch(inputValue); - return; + setUserTypedSearch(inputValue); + if (isAsync) { + setAsyncLoading(true); + debouncedLoadOptions(inputValue); } - - setAsyncLoading(true); - - debouncedLoadOptions(inputValue); }, [debouncedLoadOptions, isAsync] ); @@ -122,12 +119,16 @@ export function useOptions(rawOptions: AsyncOptions { + return isAsync ? [] : rawOptions.map(itemToString); + }, [isAsync, rawOptions]); + const finalOptions = useMemo(() => { - const currentOptions = isAsync ? asyncOptions : rawOptions.filter(itemFilter(userTypedSearch)); + const currentOptions = isAsync ? asyncOptions : fuzzyFind(rawOptions, stringifiedOptions, userTypedSearch); const currentOptionsOrganised = organizeOptionsByGroup(currentOptions); return addCustomValue(currentOptionsOrganised); - }, [isAsync, organizeOptionsByGroup, addCustomValue, asyncOptions, rawOptions, userTypedSearch]); + }, [isAsync, organizeOptionsByGroup, addCustomValue, asyncOptions, rawOptions, userTypedSearch, stringifiedOptions]); return { options: finalOptions, updateOptions, asyncLoading, asyncError }; } diff --git a/packages/grafana-ui/src/components/DateTimePickers/WeekStartPicker.tsx b/packages/grafana-ui/src/components/DateTimePickers/WeekStartPicker.tsx index aebcc7075d2..139a03713bd 100644 --- a/packages/grafana-ui/src/components/DateTimePickers/WeekStartPicker.tsx +++ b/packages/grafana-ui/src/components/DateTimePickers/WeekStartPicker.tsx @@ -7,8 +7,8 @@ import { Combobox } from '../Combobox/Combobox'; import { ComboboxOption } from '../Combobox/types'; export interface Props { - onChange: (weekStart: WeekStart) => void; - value: string; + onChange: (weekStart?: WeekStart) => void; + value?: WeekStart; width?: number; autoFocus?: boolean; onBlur?: () => void; @@ -24,9 +24,9 @@ const weekStarts: ComboboxOption[] = [ { value: 'monday', label: 'Monday' }, ]; -const isWeekStart = (value: string): value is WeekStart => { +export function isWeekStart(value: string): value is WeekStart { return ['saturday', 'sunday', 'monday'].includes(value); -}; +} declare global { interface Window { @@ -57,13 +57,13 @@ export const WeekStartPicker = (props: Props) => { const onChangeWeekStart = useCallback( (selectable: ComboboxOption | null) => { if (selectable && selectable.value !== undefined) { - onChange(selectable.value as WeekStart); + onChange(isWeekStart(selectable.value) ? selectable.value : undefined); } }, [onChange] ); - const selected = useMemo(() => weekStarts.find((item) => item.value === value)?.value ?? null, [value]); + const selected = useMemo(() => weekStarts.find((item) => item.value === value)?.value ?? '', [value]); return ( e.Threshold case "lt": return *fv < e.Threshold + case "eq": + return *fv == e.Threshold + case "ne": + return *fv != e.Threshold + case "gte": + return *fv >= e.Threshold + case "lte": + return *fv <= e.Threshold } return false @@ -113,6 +121,10 @@ func (e *rangedEvaluator) Eval(reducedValue mathexp.Number) bool { return (e.Lower < *fv && e.Upper > *fv) || (e.Upper < *fv && e.Lower > *fv) case "outside_range": return (e.Upper < *fv && e.Lower < *fv) || (e.Upper > *fv && e.Lower > *fv) + case "within_range_included": + return (e.Lower <= *fv && e.Upper >= *fv) || (e.Upper <= *fv && e.Lower >= *fv) + case "outside_range_included": + return (e.Upper <= *fv && e.Lower <= *fv) || (e.Upper >= *fv && e.Lower >= *fv) } return false diff --git a/pkg/expr/classic/evaluator_test.go b/pkg/expr/classic/evaluator_test.go index 92aa7ad2a40..4a82b1c920c 100644 --- a/pkg/expr/classic/evaluator_test.go +++ b/pkg/expr/classic/evaluator_test.go @@ -40,6 +40,48 @@ func TestThresholdEvaluator(t *testing.T) { inputNumber: newNumber(util.Pointer(1.0)), expected: true, }, + { + name: "value 1 is eq 1: false", + evaluator: &thresholdEvaluator{"eq", 1}, + inputNumber: newNumber(util.Pointer(1.0)), + expected: true, + }, + { + name: "value 0 is eq 0: false", + evaluator: &thresholdEvaluator{"eq", 0}, + inputNumber: newNumber(util.Pointer(0.0)), + expected: true, + }, + { + name: "value 1 is eq 0: false", + evaluator: &thresholdEvaluator{"eq", 0}, + inputNumber: newNumber(util.Pointer(1.0)), + expected: false, + }, + { + name: "value 0 is eq 1: false", + evaluator: &thresholdEvaluator{"eq", 1}, + inputNumber: newNumber(util.Pointer(0.0)), + expected: false, + }, + { + name: "value 1 is ne 1: false", + evaluator: &thresholdEvaluator{"ne", 1}, + inputNumber: newNumber(util.Pointer(1.0)), + expected: false, + }, + { + name: "value 3 is gte 3: false", + evaluator: &thresholdEvaluator{"gte", 3}, + inputNumber: newNumber(util.Pointer(3.0)), + expected: true, + }, + { + name: "value 5 is lte 4: false", + evaluator: &thresholdEvaluator{"lte", 4}, + inputNumber: newNumber(util.Pointer(5.0)), + expected: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/pkg/expr/query.panel.schema.json b/pkg/expr/query.panel.schema.json index 388781100ee..4437e10b82e 100644 --- a/pkg/expr/query.panel.schema.json +++ b/pkg/expr/query.panel.schema.json @@ -712,8 +712,14 @@ "enum": [ "gt", "lt", + "eq", + "ne", + "gte", + "lte", "within_range", - "outside_range" + "outside_range", + "within_range_included", + "outside_range_included" ], "x-enum-description": {} } @@ -744,8 +750,14 @@ "enum": [ "gt", "lt", + "eq", + "ne", + "gte", + "lte", "within_range", - "outside_range" + "outside_range", + "within_range_included", + "outside_range_included" ], "x-enum-description": {} } @@ -1013,4 +1025,4 @@ }, "additionalProperties": true, "$schema": "https://json-schema.org/draft-04/schema#" -} \ No newline at end of file +} diff --git a/pkg/expr/query.request.schema.json b/pkg/expr/query.request.schema.json index aa08911fc3c..5e8c4a60371 100644 --- a/pkg/expr/query.request.schema.json +++ b/pkg/expr/query.request.schema.json @@ -754,8 +754,14 @@ "enum": [ "gt", "lt", + "eq", + "ne", + "gte", + "lte", "within_range", - "outside_range" + "outside_range", + "within_range_included", + "outside_range_included" ], "x-enum-description": {} } @@ -786,8 +792,14 @@ "enum": [ "gt", "lt", + "eq", + "ne", + "gte", + "lte", "within_range", - "outside_range" + "outside_range", + "within_range_included", + "outside_range_included" ], "x-enum-description": {} } @@ -1071,4 +1083,4 @@ }, "additionalProperties": false, "$schema": "https://json-schema.org/draft-04/schema#" -} \ No newline at end of file +} diff --git a/pkg/expr/query.types.json b/pkg/expr/query.types.json index 092abaa7393..b24de7a4319 100644 --- a/pkg/expr/query.types.json +++ b/pkg/expr/query.types.json @@ -395,8 +395,14 @@ "enum": [ "gt", "lt", + "eq", + "ne", + "gte", + "lte", "within_range", - "outside_range" + "outside_range", + "within_range_included", + "outside_range_included" ], "type": "string", "x-enum-description": {} @@ -427,8 +433,14 @@ "enum": [ "gt", "lt", + "eq", + "ne", + "gte", + "lte", "within_range", - "outside_range" + "outside_range", + "within_range_included", + "outside_range_included" ], "type": "string", "x-enum-description": {} @@ -579,4 +591,4 @@ } } ] -} \ No newline at end of file +} diff --git a/pkg/expr/threshold.go b/pkg/expr/threshold.go index 127de9ce8a7..d07a5d7676e 100644 --- a/pkg/expr/threshold.go +++ b/pkg/expr/threshold.go @@ -32,18 +32,30 @@ type ThresholdCommand struct { type ThresholdType string const ( - ThresholdIsAbove ThresholdType = "gt" - ThresholdIsBelow ThresholdType = "lt" - ThresholdIsWithinRange ThresholdType = "within_range" - ThresholdIsOutsideRange ThresholdType = "outside_range" + ThresholdIsAbove ThresholdType = "gt" + ThresholdIsBelow ThresholdType = "lt" + ThresholdIsEqual ThresholdType = "eq" + ThresholdIsNotEqual ThresholdType = "ne" + ThresholdIsGreaterThanEqual ThresholdType = "gte" + ThresholdIsLessThanEqual ThresholdType = "lte" + ThresholdIsWithinRange ThresholdType = "within_range" + ThresholdIsOutsideRange ThresholdType = "outside_range" + ThresholdIsWithinRangeIncluded ThresholdType = "within_range_included" + ThresholdIsOutsideRangeIncluded ThresholdType = "outside_range_included" ) var ( supportedThresholdFuncs = []string{ string(ThresholdIsAbove), string(ThresholdIsBelow), + string(ThresholdIsEqual), + string(ThresholdIsNotEqual), + string(ThresholdIsGreaterThanEqual), + string(ThresholdIsLessThanEqual), string(ThresholdIsWithinRange), string(ThresholdIsOutsideRange), + string(ThresholdIsWithinRangeIncluded), + string(ThresholdIsOutsideRangeIncluded), } ) @@ -60,6 +72,16 @@ func NewThresholdCommand(refID, referenceVar string, thresholdFunc ThresholdType return nil, fmt.Errorf("incorrect number of arguments for threshold function '%s': got %d but need 2", thresholdFunc, len(conditions)) } predicate = withinRangePredicate{left: conditions[0], right: conditions[1]} + case ThresholdIsWithinRangeIncluded: + if len(conditions) < 2 { + return nil, fmt.Errorf("incorrect number of arguments for threshold function '%s': got %d but need 2", thresholdFunc, len(conditions)) + } + predicate = withinRangeIncludedPredicate{left: conditions[0], right: conditions[1]} + case ThresholdIsOutsideRangeIncluded: + if len(conditions) < 2 { + return nil, fmt.Errorf("incorrect number of arguments for threshold function '%s': got %d but need 2", thresholdFunc, len(conditions)) + } + predicate = outsideRangeIncludedPredicate{left: conditions[0], right: conditions[1]} case ThresholdIsAbove: if len(conditions) < 1 { return nil, fmt.Errorf("incorrect number of arguments for threshold function '%s': got %d but need 1", thresholdFunc, len(conditions)) @@ -70,6 +92,26 @@ func NewThresholdCommand(refID, referenceVar string, thresholdFunc ThresholdType return nil, fmt.Errorf("incorrect number of arguments for threshold function '%s': got %d but need 1", thresholdFunc, len(conditions)) } predicate = lessThanPredicate{value: conditions[0]} + case ThresholdIsEqual: + if len(conditions) < 1 { + return nil, fmt.Errorf("incorrect number of arguments for threshold function '%s': got %d but need 1", thresholdFunc, len(conditions)) + } + predicate = equalPredicate{value: conditions[0]} + case ThresholdIsNotEqual: + if len(conditions) < 1 { + return nil, fmt.Errorf("incorrect number of arguments for threshold function '%s': got %d but need 1", thresholdFunc, len(conditions)) + } + predicate = notEqualPredicate{value: conditions[0]} + case ThresholdIsGreaterThanEqual: + if len(conditions) < 1 { + return nil, fmt.Errorf("incorrect number of arguments for threshold function '%s': got %d but need 1", thresholdFunc, len(conditions)) + } + predicate = greaterThanEqualPredicate{value: conditions[0]} + case ThresholdIsLessThanEqual: + if len(conditions) < 1 { + return nil, fmt.Errorf("incorrect number of arguments for threshold function '%s': got %d but need 1", thresholdFunc, len(conditions)) + } + predicate = lessThanEqualPredicate{value: conditions[0]} default: return nil, fmt.Errorf("expected threshold function to be one of [%s], got %s", strings.Join(supportedThresholdFuncs, ", "), thresholdFunc) } @@ -279,6 +321,24 @@ func (r outsideRangePredicate) Eval(f float64) bool { return f < r.left || f > r.right } +type withinRangeIncludedPredicate struct { + left float64 + right float64 +} + +func (r withinRangeIncludedPredicate) Eval(f float64) bool { + return f >= r.left && f <= r.right +} + +type outsideRangeIncludedPredicate struct { + left float64 + right float64 +} + +func (r outsideRangeIncludedPredicate) Eval(f float64) bool { + return f <= r.left || f >= r.right +} + type lessThanPredicate struct { value float64 } @@ -294,3 +354,35 @@ type greaterThanPredicate struct { func (r greaterThanPredicate) Eval(f float64) bool { return f > r.value } + +type equalPredicate struct { + value float64 +} + +func (r equalPredicate) Eval(f float64) bool { + return f == r.value +} + +type notEqualPredicate struct { + value float64 +} + +func (r notEqualPredicate) Eval(f float64) bool { + return f != r.value +} + +type greaterThanEqualPredicate struct { + value float64 +} + +func (r greaterThanEqualPredicate) Eval(f float64) bool { + return f >= r.value +} + +type lessThanEqualPredicate struct { + value float64 +} + +func (r lessThanEqualPredicate) Eval(f float64) bool { + return f <= r.value +} diff --git a/pkg/expr/threshold_test.go b/pkg/expr/threshold_test.go index d458304ae08..2cfcadab18f 100644 --- a/pkg/expr/threshold_test.go +++ b/pkg/expr/threshold_test.go @@ -38,6 +38,26 @@ func TestNewThresholdCommand(t *testing.T) { args: []float64{0}, shouldError: false, }, + { + fn: "eq", + args: []float64{0}, + shouldError: false, + }, + { + fn: "ne", + args: []float64{0}, + shouldError: false, + }, + { + fn: "gte", + args: []float64{0}, + shouldError: false, + }, + { + fn: "lte", + args: []float64{0}, + shouldError: false, + }, { fn: "within_range", args: []float64{0, 1}, @@ -48,6 +68,16 @@ func TestNewThresholdCommand(t *testing.T) { args: []float64{0, 1}, shouldError: false, }, + { + fn: "within_range_included", + args: []float64{0, 1}, + shouldError: false, + }, + { + fn: "outside_range_included", + args: []float64{0, 1}, + shouldError: false, + }, { fn: "gt", args: []float64{}, @@ -60,6 +90,30 @@ func TestNewThresholdCommand(t *testing.T) { shouldError: true, expectedError: "incorrect number of arguments", }, + { + fn: "eq", + args: []float64{}, + shouldError: true, + expectedError: "incorrect number of arguments", + }, + { + fn: "ne", + args: []float64{}, + shouldError: true, + expectedError: "incorrect number of arguments", + }, + { + fn: "gte", + args: []float64{}, + shouldError: true, + expectedError: "incorrect number of arguments", + }, + { + fn: "lte", + args: []float64{}, + shouldError: true, + expectedError: "incorrect number of arguments", + }, { fn: "within_range", args: []float64{0}, @@ -72,6 +126,18 @@ func TestNewThresholdCommand(t *testing.T) { shouldError: true, expectedError: "incorrect number of arguments", }, + { + fn: "within_range_included", + args: []float64{0}, + shouldError: true, + expectedError: "incorrect number of arguments", + }, + { + fn: "outside_range_included", + args: []float64{0}, + shouldError: true, + expectedError: "incorrect number of arguments", + }, } for _, tc := range cases { @@ -249,6 +315,22 @@ func TestIsSupportedThresholdFunc(t *testing.T) { function: ThresholdIsBelow, supported: true, }, + { + function: ThresholdIsEqual, + supported: true, + }, + { + function: ThresholdIsNotEqual, + supported: true, + }, + { + function: ThresholdIsGreaterThanEqual, + supported: true, + }, + { + function: ThresholdIsLessThanEqual, + supported: true, + }, { function: ThresholdIsWithinRange, supported: true, @@ -257,6 +339,14 @@ func TestIsSupportedThresholdFunc(t *testing.T) { function: ThresholdIsOutsideRange, supported: true, }, + { + function: ThresholdIsWithinRangeIncluded, + supported: true, + }, + { + function: ThresholdIsOutsideRangeIncluded, + supported: true, + }, { function: "foo", supported: false, diff --git a/pkg/extensions/main.go b/pkg/extensions/main.go index 98e324f8e5e..b4aace2cfad 100644 --- a/pkg/extensions/main.go +++ b/pkg/extensions/main.go @@ -19,7 +19,6 @@ import ( _ "github.com/grpc-ecosystem/go-grpc-middleware/v2" _ "github.com/hashicorp/go-multierror" _ "github.com/hashicorp/golang-lru/v2" - _ "github.com/linkedin/goavro/v2" _ "github.com/m3db/prometheus_remote_client_golang/promremote" _ "github.com/phpdave11/gofpdi" _ "github.com/robfig/cron/v3" diff --git a/pkg/generated/applyconfiguration/provisioning/v0alpha1/githubrepositoryconfig.go b/pkg/generated/applyconfiguration/provisioning/v0alpha1/githubrepositoryconfig.go index 065fd444d55..e3cc1f0829c 100644 --- a/pkg/generated/applyconfiguration/provisioning/v0alpha1/githubrepositoryconfig.go +++ b/pkg/generated/applyconfiguration/provisioning/v0alpha1/githubrepositoryconfig.go @@ -4,20 +4,14 @@ package v0alpha1 -import ( - provisioningv0alpha1 "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" -) - // GitHubRepositoryConfigApplyConfiguration represents a declarative configuration of the GitHubRepositoryConfig type for use // with apply. type GitHubRepositoryConfigApplyConfiguration struct { - URL *string `json:"url,omitempty"` - Branch *string `json:"branch,omitempty"` - Token *string `json:"token,omitempty"` - EncryptedToken []byte `json:"encryptedToken,omitempty"` - Workflows []provisioningv0alpha1.Workflow `json:"workflows,omitempty"` - BranchWorkflow *bool `json:"branchWorkflow,omitempty"` - GenerateDashboardPreviews *bool `json:"generateDashboardPreviews,omitempty"` + URL *string `json:"url,omitempty"` + Branch *string `json:"branch,omitempty"` + Token *string `json:"token,omitempty"` + EncryptedToken []byte `json:"encryptedToken,omitempty"` + GenerateDashboardPreviews *bool `json:"generateDashboardPreviews,omitempty"` } // GitHubRepositoryConfigApplyConfiguration constructs a declarative configuration of the GitHubRepositoryConfig type for use with @@ -60,24 +54,6 @@ func (b *GitHubRepositoryConfigApplyConfiguration) WithEncryptedToken(values ... return b } -// WithWorkflows adds the given value to the Workflows field in the declarative configuration -// and returns the receiver, so that objects can be build by chaining "With" function invocations. -// If called multiple times, values provided by each call will be appended to the Workflows field. -func (b *GitHubRepositoryConfigApplyConfiguration) WithWorkflows(values ...provisioningv0alpha1.Workflow) *GitHubRepositoryConfigApplyConfiguration { - for i := range values { - b.Workflows = append(b.Workflows, values[i]) - } - return b -} - -// WithBranchWorkflow sets the BranchWorkflow field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the BranchWorkflow field is set to the value of the last call. -func (b *GitHubRepositoryConfigApplyConfiguration) WithBranchWorkflow(value bool) *GitHubRepositoryConfigApplyConfiguration { - b.BranchWorkflow = &value - return b -} - // WithGenerateDashboardPreviews sets the GenerateDashboardPreviews field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the GenerateDashboardPreviews field is set to the value of the last call. diff --git a/pkg/generated/applyconfiguration/provisioning/v0alpha1/repositoryspec.go b/pkg/generated/applyconfiguration/provisioning/v0alpha1/repositoryspec.go index b0d4769286d..75508c2003b 100644 --- a/pkg/generated/applyconfiguration/provisioning/v0alpha1/repositoryspec.go +++ b/pkg/generated/applyconfiguration/provisioning/v0alpha1/repositoryspec.go @@ -13,7 +13,7 @@ import ( type RepositorySpecApplyConfiguration struct { Title *string `json:"title,omitempty"` Description *string `json:"description,omitempty"` - ReadOnly *bool `json:"readOnly,omitempty"` + Workflows []provisioningv0alpha1.Workflow `json:"workflows,omitempty"` Sync *SyncOptionsApplyConfiguration `json:"sync,omitempty"` Type *provisioningv0alpha1.RepositoryType `json:"type,omitempty"` Local *LocalRepositoryConfigApplyConfiguration `json:"local,omitempty"` @@ -42,11 +42,13 @@ func (b *RepositorySpecApplyConfiguration) WithDescription(value string) *Reposi return b } -// WithReadOnly sets the ReadOnly field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the ReadOnly field is set to the value of the last call. -func (b *RepositorySpecApplyConfiguration) WithReadOnly(value bool) *RepositorySpecApplyConfiguration { - b.ReadOnly = &value +// WithWorkflows adds the given value to the Workflows field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Workflows field. +func (b *RepositorySpecApplyConfiguration) WithWorkflows(values ...provisioningv0alpha1.Workflow) *RepositorySpecApplyConfiguration { + for i := range values { + b.Workflows = append(b.Workflows, values[i]) + } return b } diff --git a/pkg/generated/applyconfiguration/provisioning/v0alpha1/syncstatus.go b/pkg/generated/applyconfiguration/provisioning/v0alpha1/syncstatus.go index 9db1d73f054..6b8f5abbac1 100644 --- a/pkg/generated/applyconfiguration/provisioning/v0alpha1/syncstatus.go +++ b/pkg/generated/applyconfiguration/provisioning/v0alpha1/syncstatus.go @@ -17,7 +17,7 @@ type SyncStatusApplyConfiguration struct { Finished *int64 `json:"finished,omitempty"` Scheduled *int64 `json:"scheduled,omitempty"` Message []string `json:"message,omitempty"` - Hash *string `json:"hash,omitempty"` + LastRef *string `json:"lastRef,omitempty"` Incremental *bool `json:"incremental,omitempty"` } @@ -77,11 +77,11 @@ func (b *SyncStatusApplyConfiguration) WithMessage(values ...string) *SyncStatus return b } -// WithHash sets the Hash field in the declarative configuration to the given value +// WithLastRef sets the LastRef field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the Hash field is set to the value of the last call. -func (b *SyncStatusApplyConfiguration) WithHash(value string) *SyncStatusApplyConfiguration { - b.Hash = &value +// If called multiple times, the LastRef field is set to the value of the last call. +func (b *SyncStatusApplyConfiguration) WithLastRef(value string) *SyncStatusApplyConfiguration { + b.LastRef = &value return b } diff --git a/pkg/registry/apis/provisioning/jobs/progress.go b/pkg/registry/apis/provisioning/jobs/progress.go new file mode 100644 index 00000000000..3a38fc902ce --- /dev/null +++ b/pkg/registry/apis/provisioning/jobs/progress.go @@ -0,0 +1,203 @@ +package jobs + +import ( + "context" + "fmt" + "time" + + "github.com/grafana/grafana-app-sdk/logging" + provisioning "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" + "github.com/grafana/grafana/pkg/registry/apis/provisioning/repository" +) + +// maybeNotifyProgress will only notify if a certain amount of time has passed +// or if the job completed +func maybeNotifyProgress(threshold time.Duration, fn ProgressFn) ProgressFn { + var last time.Time + + return func(ctx context.Context, status provisioning.JobStatus) error { + if status.Finished != 0 || last.IsZero() || time.Since(last) > threshold { + last = time.Now() + return fn(ctx, status) + } + + return nil + } +} + +// FIXME: ProgressRecorder should be initialized in the queue +type JobResourceResult struct { + Name string + Resource string + Group string + Path string + Action repository.FileAction + Error error +} + +type jobProgressRecorder struct { + started time.Time + total int + ref string + message string + resultCount int + errorCount int + errors []string + progressFn ProgressFn + summaries map[string]*provisioning.JobResourceSummary +} + +func newJobProgressRecorder(ProgressFn ProgressFn) JobProgressRecorder { + return &jobProgressRecorder{ + started: time.Now(), + progressFn: maybeNotifyProgress(5*time.Second, ProgressFn), + summaries: make(map[string]*provisioning.JobResourceSummary), + } +} + +func (r *jobProgressRecorder) Record(ctx context.Context, result JobResourceResult) { + r.resultCount++ + + logger := logging.FromContext(ctx).With("path", result.Path, "resource", result.Resource, "group", result.Group, "action", result.Action, "name", result.Name) + if result.Error != nil { + logger.Error("job resource operation failed", "err", result.Error) + if len(r.errors) < 20 { + r.errors = append(r.errors, result.Error.Error()) + } + r.errorCount++ + } else { + logger.Info("job resource operation succeeded") + } + + r.updateSummary(result) + r.notify(ctx) +} + +func (r *jobProgressRecorder) SetMessage(msg string) { + r.message = msg +} + +func (r *jobProgressRecorder) GetMessage() string { + return r.message +} + +func (r *jobProgressRecorder) SetRef(ref string) { + r.ref = ref +} + +func (r *jobProgressRecorder) GetRef() string { + return r.ref +} + +func (r *jobProgressRecorder) SetTotal(total int) { + r.total = total +} + +func (r *jobProgressRecorder) TooManyErrors() error { + if r.errorCount > 20 { + return fmt.Errorf("too many errors: %d", r.errorCount) + } + + return nil +} + +func (r *jobProgressRecorder) summary() []*provisioning.JobResourceSummary { + if len(r.summaries) == 0 { + return nil + } + + summaries := make([]*provisioning.JobResourceSummary, 0, len(r.summaries)) + for _, summary := range r.summaries { + summaries = append(summaries, summary) + } + + return summaries +} + +func (r *jobProgressRecorder) updateSummary(result JobResourceResult) { + key := result.Resource + ":" + result.Group + summary, exists := r.summaries[key] + if !exists { + summary = &provisioning.JobResourceSummary{ + Resource: result.Resource, + Group: result.Group, + } + r.summaries[key] = summary + } + + if result.Error != nil { + summary.Errors = append(summary.Errors, result.Error.Error()) + summary.Error++ + } else { + switch result.Action { + case repository.FileActionDeleted: + summary.Delete++ + case repository.FileActionUpdated: + summary.Update++ + case repository.FileActionCreated: + summary.Create++ + case repository.FileActionIgnored: + summary.Noop++ + case repository.FileActionRenamed: + summary.Delete++ + summary.Create++ + } + summary.Write = summary.Create + summary.Update + } +} + +func (r *jobProgressRecorder) progress() float64 { + if r.total == 0 { + return 0 + } + + return float64(r.resultCount) / float64(r.total) * 100 +} + +func (r *jobProgressRecorder) notify(ctx context.Context) { + jobStatus := provisioning.JobStatus{ + State: provisioning.JobStateWorking, + Message: r.message, + Errors: r.errors, + Progress: r.progress(), + Summary: r.summary(), + } + + logger := logging.FromContext(ctx) + if err := r.progressFn(ctx, jobStatus); err != nil { + logger.Warn("error notifying progress", "err", err) + } +} + +func (r *jobProgressRecorder) Complete(ctx context.Context, err error) provisioning.JobStatus { + // Initialize base job status + jobStatus := provisioning.JobStatus{ + Started: r.started.UnixMilli(), + // FIXME: if we call this method twice, the state will be different + // This results in sync status to be different from job status + Finished: time.Now().UnixMilli(), + State: provisioning.JobStateSuccess, + Message: "completed successfully", + } + + if err != nil { + jobStatus.State = provisioning.JobStateError + jobStatus.Message = err.Error() + } + + jobStatus.Summary = r.summary() + jobStatus.Errors = r.errors + + // Check for errors during execution + if len(jobStatus.Errors) > 0 && jobStatus.State != provisioning.JobStateError { + jobStatus.State = provisioning.JobStateError + jobStatus.Message = "completed with errors" + } + + // Override message if progress have a more explicit message + if r.message != "" && jobStatus.State != provisioning.JobStateError { + jobStatus.Message = r.message + } + + return jobStatus +} diff --git a/pkg/registry/apis/provisioning/jobs/queue.go b/pkg/registry/apis/provisioning/jobs/queue.go new file mode 100644 index 00000000000..cb865e91578 --- /dev/null +++ b/pkg/registry/apis/provisioning/jobs/queue.go @@ -0,0 +1,47 @@ +package jobs + +import ( + "context" + + provisioning "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" + "github.com/grafana/grafana/pkg/registry/apis/provisioning/repository" +) + +type RepoGetter interface { + GetRepository(ctx context.Context, name string) (repository.Repository, error) +} + +// Basic job queue infrastructure +type JobQueue interface { + // Add a new Job to the Queue. The status must be empty + Add(ctx context.Context, job *provisioning.Job) (*provisioning.Job, error) + + // Get the next job we should process + Next(ctx context.Context) *provisioning.Job + + // Update the status on a given job + // This is only valid if current job is not finished + Update(ctx context.Context, namespace string, name string, status provisioning.JobStatus) error + + // Register a worker (inline for now) + Register(worker Worker) +} + +type JobProgressRecorder interface { + Record(ctx context.Context, result JobResourceResult) + SetMessage(msg string) + GetMessage() string + SetRef(ref string) + GetRef() string + SetTotal(total int) + TooManyErrors() error + Complete(ctx context.Context, err error) provisioning.JobStatus +} + +type Worker interface { + IsSupported(ctx context.Context, job provisioning.Job) bool + Process(ctx context.Context, repo repository.Repository, job provisioning.Job, progress JobProgressRecorder) error +} + +// ProgressFn is a function that can be called to update the progress of a job +type ProgressFn func(ctx context.Context, status provisioning.JobStatus) error diff --git a/pkg/registry/apis/provisioning/jobs/store.go b/pkg/registry/apis/provisioning/jobs/store.go new file mode 100644 index 00000000000..89926c8828a --- /dev/null +++ b/pkg/registry/apis/provisioning/jobs/store.go @@ -0,0 +1,367 @@ +package jobs + +import ( + "context" + "errors" + "fmt" + "net/http" + "strconv" + "sync" + "time" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/apis/meta/internalversion" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/apiserver/pkg/registry/rest" + "k8s.io/apiserver/pkg/storage" + + "github.com/grafana/grafana-app-sdk/logging" + "github.com/grafana/grafana/pkg/apimachinery/identity" + provisioning "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" + "github.com/grafana/grafana/pkg/util" +) + +var ( + _ JobQueue = (*jobStore)(nil) + _ rest.Scoper = (*jobStore)(nil) + _ rest.SingularNameProvider = (*jobStore)(nil) + _ rest.Getter = (*jobStore)(nil) + _ rest.Lister = (*jobStore)(nil) + _ rest.Storage = (*jobStore)(nil) + _ rest.Watcher = (*jobStore)(nil) +) + +func NewJobStore(capacity int, getter RepoGetter) *jobStore { + return &jobStore{ + workers: make([]Worker, 0), + getter: getter, + rv: 1, + capacity: capacity, + jobs: []provisioning.Job{}, + watchSet: NewWatchSet(), + versioner: &storage.APIObjectVersioner{}, + } +} + +type jobStore struct { + getter RepoGetter + capacity int + workers []Worker + + // All jobs + jobs []provisioning.Job + rv int64 // updates whenever changed + watchSet *WatchSet + versioner storage.Versioner + + mutex sync.RWMutex +} + +// Implementing Kube interfaces + +func (s *jobStore) New() runtime.Object { + return provisioning.JobResourceInfo.NewFunc() +} + +func (s *jobStore) Destroy() {} + +func (s *jobStore) NamespaceScoped() bool { + return true // namespace == org +} + +func (s *jobStore) GetSingularName() string { + return provisioning.JobResourceInfo.GetSingularName() +} + +func (s *jobStore) NewList() runtime.Object { + return provisioning.JobResourceInfo.NewListFunc() +} + +func (s *jobStore) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) { + return provisioning.JobResourceInfo.TableConverter().ConvertToTable(ctx, object, tableOptions) +} + +func (s *jobStore) List(ctx context.Context, options *internalversion.ListOptions) (runtime.Object, error) { + ns, ok := request.NamespaceFrom(ctx) + if !ok { + return nil, fmt.Errorf("missing namespace") + } + + queue := &provisioning.JobList{ + ListMeta: metav1.ListMeta{ + ResourceVersion: strconv.FormatInt(s.rv, 10), + }, + } + + query := options.LabelSelector + + s.mutex.RLock() + defer s.mutex.RUnlock() + + for _, job := range s.jobs { + if job.Namespace != ns { + continue + } + + // maybe filter + if query != nil && !query.Matches(labels.Set(job.Labels)) { + continue + } + + copy := job.DeepCopy() + queue.Items = append(queue.Items, *copy) + } + + return queue, nil +} + +func (s *jobStore) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { + s.mutex.RLock() + defer s.mutex.RUnlock() + + ns, ok := request.NamespaceFrom(ctx) + if !ok { + return nil, fmt.Errorf("missing namespace") + } + + for _, job := range s.jobs { + if job.Name == name && job.Namespace == ns { + return job.DeepCopy(), nil + } + } + + return nil, apierrors.NewNotFound(provisioning.JobResourceInfo.GroupResource(), name) +} + +func (s *jobStore) Watch(ctx context.Context, opts *internalversion.ListOptions) (watch.Interface, error) { + ns, ok := request.NamespaceFrom(ctx) + if !ok { + return nil, fmt.Errorf("missing namespace") + } + + p := storage.SelectionPredicate{ + Label: labels.Everything(), // TODO... limit + Field: fields.Everything(), + } + + // Can watch by label selection + jw := s.watchSet.newWatch(ctx, 0, p, s.versioner, &ns) + jw.Start() + return jw, nil +} + +// Implementing JobQueue + +// Register a worker (inline for now) +func (s *jobStore) Register(worker Worker) { + s.workers = append(s.workers, worker) +} + +func (s *jobStore) Add(ctx context.Context, job *provisioning.Job) (*provisioning.Job, error) { + if job.Namespace == "" { + return nil, apierrors.NewBadRequest("missing metadata.namespace") + } + if job.Name != "" { + return nil, apierrors.NewBadRequest("name will always be generated") + } + if job.Spec.Repository == "" { + return nil, apierrors.NewBadRequest("missing spec.repository") + } + if job.Spec.Action == "" { + return nil, apierrors.NewBadRequest("missing spec.action") + } + if job.Spec.Action == provisioning.JobActionExport && job.Spec.Export == nil { + return nil, apierrors.NewBadRequest("missing spec.export") + } + + if job.Spec.Action == provisioning.JobActionSync && job.Spec.Sync == nil { + return nil, apierrors.NewBadRequest("missing spec.sync") + } + + // Only for add + if job.Status.State != "" { + return nil, apierrors.NewBadRequest("must add jobs with empty status") + } + + if job.Labels == nil { + job.Labels = make(map[string]string) + } + job.Labels["repository"] = job.Spec.Repository // for now, make sure we can search Multi-tenant + job.Name = fmt.Sprintf("%s:%s:%s", job.Spec.Repository, job.Spec.Action, util.GenerateShortUID()) + + s.mutex.Lock() + defer s.mutex.Unlock() + + s.rv++ + job.ResourceVersion = strconv.FormatInt(s.rv, 10) + job.Status.State = provisioning.JobStatePending + job.CreationTimestamp = metav1.NewTime(time.Now()) + + jobs := make([]provisioning.Job, 0, len(s.jobs)+2) + jobs = append(jobs, *job) + for i, j := range s.jobs { + if i >= s.capacity { + // Remove the old jobs + s.watchSet.notifyWatchers(watch.Event{ + Object: j.DeepCopyObject(), + Type: watch.Deleted, + }, nil) + continue + } + jobs = append(jobs, j) + } + + // Send add event + s.watchSet.notifyWatchers(watch.Event{ + Object: job.DeepCopyObject(), + Type: watch.Added, + }, nil) + + // For now, start a thread processing each job + go s.drainPending() + + s.jobs = jobs // replace existing list + return job, nil +} + +// Reads the queue until no jobs remain +func (s *jobStore) drainPending() { + logger := logging.DefaultLogger.With("logger", "job-store") + ctx := logging.Context(context.Background(), logger) + + var err error + for { + time.Sleep(time.Microsecond * 200) + + job := s.Next(ctx) + if job == nil { + return // done + } + logger := logger.With("job", job.GetName(), "namespace", job.GetNamespace()) + ctx := logging.Context(ctx, logger) + + var foundWorker bool + recorder := newJobProgressRecorder(func(ctx context.Context, j provisioning.JobStatus) error { + return s.Update(ctx, job.Namespace, job.Name, j) + }) + + for _, worker := range s.workers { + if !worker.IsSupported(ctx, *job) { + continue + } + + // Already found a worker, no need to continue + foundWorker = true + err = s.processByWorker(ctx, worker, *job, recorder) + break + } + + if !foundWorker { + err = errors.New("no registered worker supports this job") + } + + status := recorder.Complete(ctx, err) + err = s.Update(ctx, job.Namespace, job.Name, status) + if err != nil { + logger.Error("error running job", "error", err) + } + logger.Debug("job has been fully completed") + } +} + +func (s *jobStore) processByWorker(ctx context.Context, worker Worker, job provisioning.Job, recorder JobProgressRecorder) error { + ctx = request.WithNamespace(ctx, job.Namespace) + ctx, _, err := identity.WithProvisioningIdentitiy(ctx, job.Namespace) + if err != nil { + return fmt.Errorf("get worker identity: %w", err) + } + repoName := job.Spec.Repository + + logger := logging.FromContext(ctx) + logger = logger.With("repository", repoName) + ctx = logging.Context(ctx, logger) + + repo, err := s.getter.GetRepository(ctx, repoName) + if err != nil { + return fmt.Errorf("get repository: %w", err) + } + + // TODO: does this really happen? + if repo == nil { + return errors.New("unknown repository") + } + + return worker.Process(ctx, repo, job, recorder) +} + +// Checkout the next "pending" job +func (s *jobStore) Next(ctx context.Context) *provisioning.Job { + s.mutex.Lock() + defer s.mutex.Unlock() + + // The oldest jobs should be checked out first + for i := len(s.jobs) - 1; i >= 0; i-- { + if s.jobs[i].Status.State == provisioning.JobStatePending { + oldObj := s.jobs[i].DeepCopyObject() + + s.rv++ + s.jobs[i].ResourceVersion = strconv.FormatInt(s.rv, 10) + s.jobs[i].Status.State = provisioning.JobStateWorking + s.jobs[i].Status.Started = time.Now().UnixMilli() + job := s.jobs[i] + + s.watchSet.notifyWatchers(watch.Event{ + Object: job.DeepCopyObject(), + Type: watch.Modified, + }, oldObj) + return &job + } + } + return nil +} + +func (s *jobStore) Update(ctx context.Context, namespace string, name string, status provisioning.JobStatus) error { + s.mutex.Lock() + defer s.mutex.Unlock() + + s.rv++ + + if status.State == "" { + return apierrors.NewBadRequest("The state must be set") + } + if status.Progress > 100 || status.Progress < 0 { + return apierrors.NewBadRequest("progress must be between 0 and 100") + } + + for idx, job := range s.jobs { + if job.Name == name && job.Namespace == namespace { + if job.Status.State.Finished() { + return &apierrors.StatusError{ErrStatus: metav1.Status{ + Code: http.StatusPreconditionFailed, + Message: "The job is already finished and can not be updated", + }} + } + if status.State.Finished() { + status.Finished = time.Now().UnixMilli() + } + + oldObj := job.DeepCopyObject() + job.ResourceVersion = strconv.FormatInt(s.rv, 10) + job.Status = status + s.jobs[idx] = job + + s.watchSet.notifyWatchers(watch.Event{ + Object: job.DeepCopyObject(), + Type: watch.Modified, + }, oldObj) + return nil + } + } + + return apierrors.NewNotFound(provisioning.JobResourceInfo.GroupResource(), name) +} diff --git a/pkg/registry/apis/provisioning/jobs/watchset.go b/pkg/registry/apis/provisioning/jobs/watchset.go new file mode 100644 index 00000000000..f9a2934482d --- /dev/null +++ b/pkg/registry/apis/provisioning/jobs/watchset.go @@ -0,0 +1,379 @@ +// SPDX-License-Identifier: AGPL-3.0-only +// Provenance-includes-location: https://github.com/tilt-dev/tilt-apiserver/blob/main/pkg/storage/filepath/watchset.go +// Provenance-includes-license: Apache-2.0 +// Provenance-includes-copyright: The Kubernetes Authors. + +// See also +// https://github.com/grafana/grafana/blob/v11.1.9/pkg/apiserver/storage/file/watchset.go + +package jobs + +import ( + "context" + "fmt" + "sync" + "sync/atomic" + + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/apiserver/pkg/storage" + "k8s.io/klog/v2" +) + +const ( + UpdateChannelSize = 25 + InitialWatchNodesSize = 20 + InitialBufferedEventsSize = 25 +) + +type eventWrapper struct { + ev watch.Event + // optional: oldObject is only set for modifications for determining their type as necessary (when using predicate filtering) + oldObject runtime.Object +} + +type watchNode struct { + ctx context.Context + s *WatchSet + id uint64 + updateCh chan eventWrapper + outCh chan watch.Event + requestedRV uint64 + // the watch may or may not be namespaced for a namespaced resource. This is always nil for cluster-scoped kinds + watchNamespace *string + predicate storage.SelectionPredicate + versioner storage.Versioner +} + +// Keeps track of which watches need to be notified +type WatchSet struct { + mu sync.RWMutex + // mu protects both nodes and counter + nodes map[uint64]*watchNode + counter atomic.Uint64 + buffered []eventWrapper + bufferedMutex sync.RWMutex +} + +func NewWatchSet() *WatchSet { + return &WatchSet{ + buffered: make([]eventWrapper, 0, InitialBufferedEventsSize), + nodes: make(map[uint64]*watchNode, InitialWatchNodesSize), + } +} + +// Creates a new watch with a unique id, but +// does not start sending events to it until start() is called. +func (s *WatchSet) newWatch(ctx context.Context, requestedRV uint64, p storage.SelectionPredicate, versioner storage.Versioner, namespace *string) *watchNode { + s.counter.Add(1) + + node := &watchNode{ + ctx: ctx, + requestedRV: requestedRV, + id: s.counter.Load(), + s: s, + // updateCh size needs to be > 1 to allow slower clients to not block passing new events + updateCh: make(chan eventWrapper, UpdateChannelSize), + // outCh size needs to be > 1 for single process use-cases such as tests where watch and event seeding from CUD + // events is happening on the same thread + outCh: make(chan watch.Event, UpdateChannelSize), + predicate: p, + watchNamespace: namespace, + versioner: versioner, + } + + return node +} + +func (s *WatchSet) CleanupWatchers() { + s.mu.Lock() + defer s.mu.Unlock() + for _, w := range s.nodes { + w.stop() + } +} + +// oldObject is only passed in the event of a modification +// in case a predicate filtered watch is impacted as a result of modification +// NOTE: this function gives one the misperception that a newly added node will never +// get a double event, one from buffered and one from the update channel +// That perception is not true. Even though this function maintains the lock throughout the function body +// it is not true of the Start function. So basically, the Start function running after this function +// fully stands the chance of another future notifyWatchers double sending it the event through the two means mentioned +func (s *WatchSet) notifyWatchers(ev watch.Event, oldObject runtime.Object) { + s.mu.RLock() + defer s.mu.RUnlock() + + updateEv := eventWrapper{ + ev: ev, + } + if oldObject != nil { + updateEv.oldObject = oldObject + } + + // Events are always buffered. + // this is because of an inadvertent delay which is built into the watch process + // Watch() from storage returns Watch.Interface with a async start func. + // The only way to guarantee that we can interpret the passed RV correctly is to play it against missed events + // (notice the loop below over s.nodes isn't exactly going to work on a new node + // unless start is called on it) + s.bufferedMutex.Lock() + s.buffered = append(s.buffered, updateEv) + s.bufferedMutex.Unlock() + + for _, w := range s.nodes { + w.updateCh <- updateEv + } +} + +// isValid is not necessary to be called on oldObject in UpdateEvents - assuming the Watch pushes correctly setup eventWrapper our way +// first bool is whether the event is valid for current watcher +// second bool is whether checking the old value against the predicate may be valuable to the caller +// second bool may be a helpful aid to establish context around MODIFIED events +// (note that this second bool is only marked true if we pass other checks first, namely RV and namespace) +func (w *watchNode) isValid(e eventWrapper) (bool, bool, error) { + obj, err := meta.Accessor(e.ev.Object) + if err != nil { + klog.Error("Could not get accessor to object in event") + return false, false, nil + } + + eventRV, err := w.getResourceVersionAsInt(e.ev.Object) + if err != nil { + return false, false, err + } + + if eventRV < w.requestedRV { + return false, false, nil + } + + if w.watchNamespace != nil && *w.watchNamespace != obj.GetNamespace() { + return false, false, err + } + + valid, err := w.predicate.Matches(e.ev.Object) + if err != nil { + return false, false, err + } + + return valid, e.ev.Type == watch.Modified, nil +} + +// Only call this method if current object matches the predicate +func (w *watchNode) handleAddedForFilteredList(e eventWrapper) (*watch.Event, error) { + if e.oldObject == nil { + return nil, fmt.Errorf("oldObject should be set for modified events") + } + + ok, err := w.predicate.Matches(e.oldObject) + if err != nil { + return nil, err + } + + if !ok { + e.ev.Type = watch.Added + return &e.ev, nil + } + + return nil, nil +} + +func (w *watchNode) handleDeletedForFilteredList(e eventWrapper) (*watch.Event, error) { + if e.oldObject == nil { + return nil, fmt.Errorf("oldObject should be set for modified events") + } + + ok, err := w.predicate.Matches(e.oldObject) + if err != nil { + return nil, err + } + + if !ok { + return nil, nil + } + + // isn't a match but used to be + e.ev.Type = watch.Deleted + + oldObjectAccessor, err := meta.Accessor(e.oldObject) + if err != nil { + klog.Errorf("Could not get accessor to correct the old RV of filtered out object") + return nil, err + } + + currentRV, err := getResourceVersion(e.ev.Object) + if err != nil { + klog.Errorf("Could not get accessor to object in event") + return nil, err + } + + oldObjectAccessor.SetResourceVersion(currentRV) + e.ev.Object = e.oldObject + + return &e.ev, nil +} + +func (w *watchNode) processEvent(e eventWrapper, isInitEvent bool) error { + if isInitEvent { + // Init events have already been vetted against the predicate and other RV behavior + // Let them pass through + w.outCh <- e.ev + return nil + } + + valid, runDeleteFromFilteredListHandler, err := w.isValid(e) + if err != nil { + klog.Errorf("Could not determine validity of the event: %v", err) + return err + } + if valid { + if e.ev.Type == watch.Modified { + ev, err := w.handleAddedForFilteredList(e) + if err != nil { + return err + } + if ev != nil { + w.outCh <- *ev + } else { + // forward the original event if add handling didn't signal any impact + w.outCh <- e.ev + } + } else { + w.outCh <- e.ev + } + return nil + } + + if runDeleteFromFilteredListHandler { + if e.ev.Type == watch.Modified { + ev, err := w.handleDeletedForFilteredList(e) + if err != nil { + return err + } + if ev != nil { + w.outCh <- *ev + } + } // explicitly doesn't have an event forward for the else case here + return nil + } + + return nil +} + +// Start sending events to this watch. +func (w *watchNode) Start(initEvents ...watch.Event) { + w.s.mu.Lock() + w.s.nodes[w.id] = w + w.s.mu.Unlock() + + go func() { + maxRV := uint64(0) + for _, ev := range initEvents { + currentRV, err := w.getResourceVersionAsInt(ev.Object) + if err != nil { + klog.Errorf("Could not determine init event RV for deduplication of buffered events: %v", err) + continue + } + + if maxRV < currentRV { + maxRV = currentRV + } + + if err := w.processEvent(eventWrapper{ev: ev}, true); err != nil { + klog.Errorf("Could not process event: %v", err) + } + } + + // If we had no init events, simply rely on the passed RV + if maxRV == 0 { + maxRV = w.requestedRV + } + + w.s.bufferedMutex.RLock() + for _, e := range w.s.buffered { + eventRV, err := w.getResourceVersionAsInt(e.ev.Object) + if err != nil { + klog.Errorf("Could not determine RV for deduplication of buffered events: %v", err) + continue + } + + if maxRV >= eventRV { + continue + } else { + maxRV = eventRV + } + + if err := w.processEvent(e, false); err != nil { + klog.Errorf("Could not process event: %v", err) + } + } + w.s.bufferedMutex.RUnlock() + + for { + select { + case e, ok := <-w.updateCh: + if !ok { + close(w.outCh) + return + } + + eventRV, err := w.getResourceVersionAsInt(e.ev.Object) + if err != nil { + klog.Errorf("Could not determine RV for deduplication of channel events: %v", err) + continue + } + + if maxRV >= eventRV { + continue + } else { + maxRV = eventRV + } + + if err := w.processEvent(e, false); err != nil { + klog.Errorf("Could not process event: %v", err) + } + case <-w.ctx.Done(): + close(w.outCh) + return + } + } + }() +} + +func (w *watchNode) Stop() { + w.s.mu.Lock() + defer w.s.mu.Unlock() + w.stop() +} + +// Unprotected func: ensure mutex on the parent watch set is locked before calling +func (w *watchNode) stop() { + if _, ok := w.s.nodes[w.id]; ok { + delete(w.s.nodes, w.id) + close(w.updateCh) + } +} + +func (w *watchNode) ResultChan() <-chan watch.Event { + return w.outCh +} + +func getResourceVersion(obj runtime.Object) (string, error) { + accessor, err := meta.Accessor(obj) + if err != nil { + klog.Error("Could not get accessor to object in event") + return "", err + } + return accessor.GetResourceVersion(), nil +} + +func (w *watchNode) getResourceVersionAsInt(obj runtime.Object) (uint64, error) { + accessor, err := meta.Accessor(obj) + if err != nil { + klog.Error("Could not get accessor to object in event") + return 0, err + } + + return w.versioner.ParseResourceVersion(accessor.GetResourceVersion()) +} diff --git a/pkg/registry/apis/provisioning/register.go b/pkg/registry/apis/provisioning/register.go index 3171f55c66a..d5a12275733 100644 --- a/pkg/registry/apis/provisioning/register.go +++ b/pkg/registry/apis/provisioning/register.go @@ -6,8 +6,12 @@ import ( provisioning "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" grafanaregistry "github.com/grafana/grafana/pkg/apiserver/registry/generic" + "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs" + "github.com/grafana/grafana/pkg/registry/apis/provisioning/repository" + "github.com/grafana/grafana/pkg/registry/apis/provisioning/secrets" "github.com/grafana/grafana/pkg/services/apiserver/builder" "github.com/grafana/grafana/pkg/services/featuremgmt" + grafanasecrets "github.com/grafana/grafana/pkg/services/secrets" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -22,16 +26,28 @@ import ( ) var ( - _ builder.APIGroupBuilder = (*APIBuilder)(nil) + _ builder.APIGroupBuilder = (*APIBuilder)(nil) + _ builder.APIGroupMutation = (*APIBuilder)(nil) + _ builder.APIGroupValidation = (*APIBuilder)(nil) + _ builder.APIGroupPostStartHookProvider = (*APIBuilder)(nil) + _ builder.OpenAPIPostProcessor = (*APIBuilder)(nil) ) -type APIBuilder struct{} +type APIBuilder struct { + secrets secrets.Service + jobs jobs.JobQueue + getter rest.Getter +} // NewAPIBuilder creates an API builder. // It avoids anything that is core to Grafana, such that it can be used in a multi-tenant service down the line. // This means there are no hidden dependencies, and no use of e.g. *settings.Cfg. -func NewAPIBuilder() *APIBuilder { - return &APIBuilder{} +func NewAPIBuilder( + secrets secrets.Service, +) *APIBuilder { + return &APIBuilder{ + secrets: secrets, + } } // RegisterAPIService returns an API builder, from [NewAPIBuilder]. It is called by Wire. @@ -39,13 +55,14 @@ func NewAPIBuilder() *APIBuilder { func RegisterAPIService( features featuremgmt.FeatureToggles, apiregistration builder.APIRegistrar, + secretsSvc grafanasecrets.Service, ) (*APIBuilder, error) { if !features.IsEnabledGlobally(featuremgmt.FlagProvisioning) && !features.IsEnabledGlobally(featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs) { return nil, nil // skip registration unless opting into experimental apis OR the feature specifically } - builder := NewAPIBuilder() + builder := NewAPIBuilder(secrets.NewSingleTenant(secretsSvc)) apiregistration.RegisterAPI(builder) return builder, nil } @@ -87,9 +104,14 @@ func (b *APIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupI return fmt.Errorf("failed to create repository storage: %w", err) } + // FIXME: Make job queue store the jobs somewhere persistent. + jobStore := jobs.NewJobStore(50, b) // in memory, for now... + b.jobs = jobStore + repositoryStatusStorage := grafanaregistry.NewRegistryStatusStore(opts.Scheme, repositoryStorage) storage := map[string]rest.Storage{} + storage[provisioning.JobResourceInfo.StoragePath()] = jobStore storage[provisioning.RepositoryResourceInfo.StoragePath()] = repositoryStorage storage[provisioning.RepositoryResourceInfo.StoragePath("status")] = repositoryStatusStorage apiGroupInfo.VersionedResourcesStorageMap[provisioning.VERSION] = storage @@ -158,3 +180,16 @@ func (b *APIBuilder) PostProcessOpenAPI(oas *spec3.OpenAPI) (*spec3.OpenAPI, err return oas, nil } + +// Helpers for fetching valid Repository objects + +func (b *APIBuilder) GetRepository(ctx context.Context, name string) (repository.Repository, error) { + obj, err := b.getter.Get(ctx, name, &metav1.GetOptions{}) + if err != nil { + return nil, err + } + + _ = obj + // FIXME: Return a valid Repository object with the correct underlying storage. + panic("FIXME") +} diff --git a/pkg/registry/apis/provisioning/repository/repository.go b/pkg/registry/apis/provisioning/repository/repository.go new file mode 100644 index 00000000000..d4dd2aee63d --- /dev/null +++ b/pkg/registry/apis/provisioning/repository/repository.go @@ -0,0 +1,128 @@ +package repository + +import ( + "context" + "io/fs" + "net/http" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/validation/field" + + provisioning "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" +) + +type Repository interface { + // Config returns the saved Kubernetes object. + Config() *provisioning.Repository + + // Validate ensures the resource _looks_ correct. + // It should be called before trying to upsert a resource into the Kubernetes API server. + // This is not an indication that the connection information works, just that they are reasonably configured (see also Test). + Validate() field.ErrorList + + // Test checks if the connection information actually works. + Test(ctx context.Context) (*provisioning.TestResults, error) +} + +// ErrFileNotFound indicates that a path could not be found in the repository. +var ErrFileNotFound error = fs.ErrNotExist + +type FileInfo struct { + // Path to the file on disk. + // No leading or trailing slashes will be contained within. + // This uses '/' for separation. Use the 'path' package to interact with this. + Path string + // The raw bytes + Data []byte + // The git branch or reference commit + Ref string + // The git hash for a given file + Hash string + // When was the file changed (if known) + Modified *metav1.Time +} + +// An entry in the file tree, as returned by 'ReadFileTree'. Like FileInfo, but contains less information. +type FileTreeEntry struct { + // The path to the file from the base path given (if any). + // No leading or trailing slashes will be contained within. + // This uses '/' for separation. Use the 'path' package to interact with this. + Path string + // The hash for the file. Lower-case hex. + // Empty string if Blob is false. + Hash string + // The size of the file. + // 0 if Blob is false. + Size int64 + // Whether this entry is a blob or a subtree. + Blob bool +} + +type Reader interface { + // Read a file from the resource + // This data will be parsed and validated before it is shown to end users + Read(ctx context.Context, path, ref string) (*FileInfo, error) + + // Read all file names from the tree. + // This data will be parsed and validated before it is shown. + // + // TODO: Make some API contract that lets us ignore files that aren't relevant to us (e.g. CI/CD, CODEOWNERS, other configs or source code). + // TODO: Test scale: do we want to stream entries instead somehow? + ReadTree(ctx context.Context, ref string) ([]FileTreeEntry, error) +} + +type Writer interface { + // Write a file to the repository. + // The data has already been validated and is ready for save + Create(ctx context.Context, path, ref string, data []byte, message string) error + + // Update a file in the remote repository + // The data has already been validated and is ready for save + Update(ctx context.Context, path, ref string, data []byte, message string) error + + // Write a file to the repository. + // Functionally the same as Read then Create or Update, but more efficient depending on the backend + Write(ctx context.Context, path, ref string, data []byte, message string) error + + // Delete a file in the remote repository + Delete(ctx context.Context, path, ref, message string) error +} + +// Hooks called after the repository has been created, updated or deleted +type Hooks interface { + // For repositories that support webhooks + Webhook(ctx context.Context, req *http.Request) (*provisioning.WebhookResponse, error) + OnCreate(ctx context.Context) (*provisioning.WebhookStatus, error) + OnUpdate(ctx context.Context) (*provisioning.WebhookStatus, error) + OnDelete(ctx context.Context) error +} + +type FileAction string + +const ( + FileActionCreated FileAction = "created" + FileActionUpdated FileAction = "updated" + FileActionDeleted FileAction = "deleted" + FileActionIgnored FileAction = "ignored" + + // Renamed actions may be reconstructed as delete then create + FileActionRenamed FileAction = "renamed" +) + +type VersionedFileChange struct { + Action FileAction + Path string + + Ref string + PreviousRef string // rename | update + PreviousPath string // rename +} + +// Versioned is a repository that supports versioning. +// This interface may be extended to make the the original Repository interface more agnostic to the underlying storage system. +type Versioned interface { + // History of changes for a path + History(ctx context.Context, path, ref string) ([]provisioning.HistoryItem, error) + LatestRef(ctx context.Context) (string, error) + CompareFiles(ctx context.Context, base, ref string) ([]VersionedFileChange, error) +} diff --git a/pkg/registry/apis/provisioning/safepath/path.go b/pkg/registry/apis/provisioning/safepath/path.go new file mode 100644 index 00000000000..17f0adb18f9 --- /dev/null +++ b/pkg/registry/apis/provisioning/safepath/path.go @@ -0,0 +1,59 @@ +package safepath + +import ( + "os" + "path" + "strings" + + apierrors "k8s.io/apimachinery/pkg/api/errors" +) + +// ErrUnsafePathTraversal indicates that an input path had a path traversal which led to escaping the required prefix. +// E.g. Join("/test", "..") would return this, because it doesn't stay within the '/test' directory. +var ErrUnsafePathTraversal = apierrors.NewBadRequest("the input path had an unacceptable path traversal") + +// Join joins any number of elements in a path under a common prefix path. +// If the elems do path traversal, they are permitted to do so under their own directories. +// The output result will _always_ have a prefix of the given prefix, and no path traversals in the output string. +// The output result will not end with a trailing slash. +// The output result will have a leading slash if one is given as a prefix. +// If the prefix would ultimately be escaped, an error is returned. +// +// This function is safe for . +func Join(prefix string, elem ...string) (string, error) { + // We clean early to make the HasPrefix check be sensible after path.Join does a Clean for us. + prefix = replaceOSSeparators(path.Clean(prefix)) + if len(elem) == 0 { + return prefix, nil + } + + for i, e := range elem { + // We don't use Clean here because the output of path.Join will clean for us. + elem[i] = replaceOSSeparators(e) + } + subPath := path.Join(elem...) // performs a Clean after joining + completePath := path.Join(prefix, subPath) + if !strings.HasPrefix(completePath, prefix) { + return "", ErrUnsafePathTraversal + } + return completePath, nil +} + +// Performs a [path.Clean] on the path, as well as replacing its OS separators. +// Note that this does no effort to ensure the paths are safe to use. It only cleans them. +func Clean(p string) string { + return path.Clean(replaceOSSeparators(p)) +} + +// osSeparator is declared as a var here only to ensure we can change it in tests. +var osSeparator = os.PathSeparator + +// This replaces the OS separator with a slash. +// All OSes we target (Linux, macOS, and Windows) support forward-slashes in path traversals, as such it's simpler to use the same character everywhere. +// BSDs do as well (even though they're not a target as of writing). +func replaceOSSeparators(p string) string { + if osSeparator == '/' { // perf: nothing to do! + return p + } + return strings.ReplaceAll(p, string(osSeparator), "/") +} diff --git a/pkg/registry/apis/provisioning/safepath/path_test.go b/pkg/registry/apis/provisioning/safepath/path_test.go new file mode 100644 index 00000000000..abd4f14abc1 --- /dev/null +++ b/pkg/registry/apis/provisioning/safepath/path_test.go @@ -0,0 +1,74 @@ +package safepath + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestPathJoin(t *testing.T) { + orig := osSeparator + osSeparator = '\\' // pretend we're on Windows + defer func() { osSeparator = orig }() + + testCases := []struct { + Comment string + In []string + Out any // string or error + }{ + {"Empty elements should not change input", []string{"/test/"}, "/test"}, + {"Empty elements without leading slash should not change input", []string{"test/"}, "test"}, + {"Single element should be added to path", []string{"/test/", "abc"}, "/test/abc"}, + {"Single element should be added to path with current dir prefix", []string{"./test/", "abc"}, "test/abc"}, + {"Single element with leading slash should be added to path", []string{"/test/", "/abc"}, "/test/abc"}, + {"Many elements are all appended to path", []string{"/test/", "a", "b", "c"}, "/test/a/b/c"}, + {"Path traversal within same directory should be expanded", []string{"/test/", "a", "..", "b", ".", "..", "c"}, "/test/c"}, + {"Path traversal escaping root dir prefix should return err", []string{"/test/", ".."}, ErrUnsafePathTraversal}, + {"Path traversal escaping no dir prefix should return err", []string{"test/", ".."}, ErrUnsafePathTraversal}, + {"Path traversal escaping current dir prefix should return err", []string{"./test/", ".."}, ErrUnsafePathTraversal}, + {"Complex path traversal escaping prefix should return err", []string{"/test/", "a/..///c/", "../../test/d/../a/../.."}, ErrUnsafePathTraversal}, + {"Complex path traversal remaining in prefix should be expanded", []string{"/test/", "a/..///c/", "../../test/d/"}, "/test/d"}, + {"Problematic code example from the g304 website", []string{"/safe/path", "../../private/path"}, ErrUnsafePathTraversal}, + {"Traversing beyond root should be expanded", []string{"/test/", "/../a"}, "/test/a"}, + {"OS separator should be replaced with a slash", []string{"/test\\test", "abc\\test"}, "/test/test/abc/test"}, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.Comment, func(t *testing.T) { + path, err := Join(tc.In[0], tc.In[1:]...) + if ee, ok := tc.Out.(error); ok { + assert.ErrorIs(t, err, ee, "expected unsuccessful outcome") + assert.Empty(t, path, "expected empty string when unsuccessful") + } else if str, ok := tc.Out.(string); ok { + assert.NoError(t, err, "expected successful outcome") + assert.Equal(t, str, path) + } else { + panic("expected out was neither string nor error") + } + }) + } +} + +func TestPathClean(t *testing.T) { + orig := osSeparator + osSeparator = '\\' // pretend we're on Windows + defer func() { osSeparator = orig }() + + testCases := []struct { + Comment string + In string + Out string + }{ + {"Simple path", "/test/", "/test"}, + {"Simple path with OS separators", "\\test\\here", "/test/here"}, + {"Simple path with mixed separators", "\\test/here", "/test/here"}, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.Comment, func(t *testing.T) { + assert.Equal(t, tc.Out, Clean(tc.In)) + }) + } +} diff --git a/pkg/registry/apis/provisioning/safepath/walk.go b/pkg/registry/apis/provisioning/safepath/walk.go new file mode 100644 index 00000000000..57a6c4a9bb6 --- /dev/null +++ b/pkg/registry/apis/provisioning/safepath/walk.go @@ -0,0 +1,31 @@ +package safepath + +import ( + "context" + "path" + "strings" +) + +type WalkFunc = func(ctx context.Context, path string) error + +// Walk walks the given folder path and calls the given function for each folder. +func Walk(ctx context.Context, p string, fn WalkFunc) error { + if p == "." || p == "/" { + return nil + } + + var currentPath string + for _, folder := range strings.Split(p, "/") { + if folder == "" { + // Trailing / leading slash? + continue + } + + currentPath = path.Join(currentPath, folder) + if err := fn(ctx, currentPath); err != nil { + return err + } + } + + return nil +} diff --git a/pkg/registry/apis/provisioning/secrets/secret.go b/pkg/registry/apis/provisioning/secrets/secret.go new file mode 100644 index 00000000000..f0e8498825d --- /dev/null +++ b/pkg/registry/apis/provisioning/secrets/secret.go @@ -0,0 +1,35 @@ +package secrets + +import ( + "context" + + "github.com/grafana/grafana/pkg/services/secrets" +) + +// A secrets encryption service. It only operates on values, no names or similar. +// It is likely we will need to change this when the multi-tenant service comes around. +// +// FIXME: this is a temporary service/package until we can make use of +// the new secrets service in app platform. +type Service interface { + Encrypt(ctx context.Context, data []byte) ([]byte, error) + Decrypt(ctx context.Context, data []byte) ([]byte, error) +} + +var _ Service = (*singleTenant)(nil) + +type singleTenant struct { + inner secrets.Service +} + +func NewSingleTenant(svc secrets.Service) *singleTenant { + return &singleTenant{svc} +} + +func (s *singleTenant) Encrypt(ctx context.Context, data []byte) ([]byte, error) { + return s.inner.Encrypt(ctx, data, secrets.WithoutScope()) +} + +func (s *singleTenant) Decrypt(ctx context.Context, data []byte) ([]byte, error) { + return s.inner.Decrypt(ctx, data) +} diff --git a/pkg/services/annotations/annotationsimpl/loki/historian_store.go b/pkg/services/annotations/annotationsimpl/loki/historian_store.go index 563d4435be7..5bc4e02d303 100644 --- a/pkg/services/annotations/annotationsimpl/loki/historian_store.go +++ b/pkg/services/annotations/annotationsimpl/loki/historian_store.go @@ -91,20 +91,22 @@ func (r *LokiHistorianStore) Get(ctx context.Context, query annotations.ItemQuer return make([]*annotations.ItemDTO, 0), nil } - rule := &ngmodels.AlertRule{} - if query.AlertID != 0 { - var err error - rule, err = r.ruleStore.GetRuleByID(ctx, ngmodels.GetAlertRuleByIDQuery{OrgID: query.OrgID, ID: query.AlertID}) + var ruleUID string + if query.AlertUID != "" { + ruleUID = query.AlertUID + } else if query.AlertID != 0 { + rule, err := r.ruleStore.GetRuleByID(ctx, ngmodels.GetAlertRuleByIDQuery{OrgID: query.OrgID, ID: query.AlertID}) if err != nil { if errors.Is(err, ngmodels.ErrAlertRuleNotFound) { return make([]*annotations.ItemDTO, 0), ErrLokiStoreNotFound.Errorf("rule with ID %d does not exist", query.AlertID) } return make([]*annotations.ItemDTO, 0), ErrLokiStoreInternal.Errorf("failed to query rule: %w", err) } + ruleUID = rule.UID } // No folders in the filter because it filter by Dashboard UID, and the request is already authorized. - logQL, err := historian.BuildLogQuery(buildHistoryQuery(&query, accessResources.Dashboards, rule.UID), nil, r.client.MaxQuerySize()) + logQL, err := historian.BuildLogQuery(buildHistoryQuery(&query, accessResources.Dashboards, ruleUID), nil, r.client.MaxQuerySize()) if err != nil { grafanaErr := errutil.Error{} if errors.As(err, &grafanaErr) { diff --git a/pkg/services/annotations/annotationsimpl/loki/historian_store_test.go b/pkg/services/annotations/annotationsimpl/loki/historian_store_test.go index f4e4bf6630a..67ebca32918 100644 --- a/pkg/services/annotations/annotationsimpl/loki/historian_store_test.go +++ b/pkg/services/annotations/annotationsimpl/loki/historian_store_test.go @@ -108,7 +108,34 @@ func TestIntegrationAlertStateHistoryStore(t *testing.T) { require.Len(t, res, numTransitions) }) - t.Run("should return ErrLokiStoreNotFound if rule is not found", func(t *testing.T) { + t.Run("can query history by alert uid", func(t *testing.T) { + rule := dashboardRules[dashboard1.UID][0] + + fakeLokiClient.rangeQueryRes = []historian.Stream{ + historian.StatesToStream(ruleMetaFromRule(t, rule), transitions, map[string]string{}, log.NewNopLogger()), + } + + query := annotations.ItemQuery{ + OrgID: 1, + AlertUID: rule.UID, + From: start.UnixMilli(), + To: start.Add(time.Second * time.Duration(numTransitions+1)).UnixMilli(), + } + res, err := store.Get( + context.Background(), + query, + &annotation_ac.AccessResources{ + Dashboards: map[string]int64{ + dashboard1.UID: dashboard1.ID, + }, + CanAccessDashAnnotations: true, + }, + ) + require.NoError(t, err) + require.Len(t, res, numTransitions) + }) + + t.Run("should return ErrLokiStoreNotFound if rule is not found by ID", func(t *testing.T) { var rules = slices.Concat(maps.Values(dashboardRules)...) id := rand.Int63n(1000) // in Postgres ID is integer, so limit range // make sure id is not known @@ -137,6 +164,27 @@ func TestIntegrationAlertStateHistoryStore(t *testing.T) { require.ErrorIs(t, err, ErrLokiStoreNotFound) }) + t.Run("should return empty response if rule is not found by UID", func(t *testing.T) { + query := annotations.ItemQuery{ + OrgID: 1, + AlertUID: "not-found-uid", + From: start.UnixMilli(), + To: start.Add(time.Second * time.Duration(numTransitions+1)).UnixMilli(), + } + res, err := store.Get( + context.Background(), + query, + &annotation_ac.AccessResources{ + Dashboards: map[string]int64{ + dashboard1.UID: dashboard1.ID, + }, + CanAccessDashAnnotations: true, + }, + ) + require.NoError(t, err) + require.Empty(t, res) + }) + t.Run("can query history by dashboard id", func(t *testing.T) { fakeLokiClient.rangeQueryRes = []historian.Stream{ historian.StatesToStream(ruleMetaFromRule(t, dashboardRules[dashboard1.UID][0]), transitions, map[string]string{}, log.NewNopLogger()), diff --git a/pkg/services/annotations/annotationsimpl/xorm_store.go b/pkg/services/annotations/annotationsimpl/xorm_store.go index 603ec3865e8..7b957189312 100644 --- a/pkg/services/annotations/annotationsimpl/xorm_store.go +++ b/pkg/services/annotations/annotationsimpl/xorm_store.go @@ -267,10 +267,10 @@ func (r *xormRepositoryImpl) Get(ctx context.Context, query annotations.ItemQuer annotation.updated, usr.email, usr.login, - alert.name as alert_name + r.title as alert_name FROM annotation LEFT OUTER JOIN ` + r.db.GetDialect().Quote("user") + ` as usr on usr.id = annotation.user_id - LEFT OUTER JOIN alert on alert.id = annotation.alert_id + LEFT OUTER JOIN alert_rule as r on r.id = annotation.alert_id INNER JOIN ( SELECT a.id from annotation a `) @@ -287,6 +287,9 @@ func (r *xormRepositoryImpl) Get(ctx context.Context, query annotations.ItemQuer if query.AlertID != 0 { sql.WriteString(` AND a.alert_id = ?`) params = append(params, query.AlertID) + } else if query.AlertUID != "" { + sql.WriteString(` AND a.alert_id = (SELECT id FROM alert_rule WHERE uid = ? and org_id = ?)`) + params = append(params, query.AlertUID, query.OrgID) } if query.DashboardID != 0 { diff --git a/pkg/services/annotations/models.go b/pkg/services/annotations/models.go index c9f22140d6f..9dcd23755ea 100644 --- a/pkg/services/annotations/models.go +++ b/pkg/services/annotations/models.go @@ -11,6 +11,7 @@ type ItemQuery struct { To int64 `json:"to"` UserID int64 `json:"userId"` AlertID int64 `json:"alertId"` + AlertUID string `json:"alertUID"` DashboardID int64 `json:"dashboardId"` DashboardUID string `json:"dashboardUID"` PanelID int64 `json:"panelId"` diff --git a/pkg/services/authz/rbac.go b/pkg/services/authz/rbac.go index f83a2b4d4a7..fcb398667ab 100644 --- a/pkg/services/authz/rbac.go +++ b/pkg/services/authz/rbac.go @@ -151,20 +151,24 @@ func RegisterRBACAuthZService( reg prometheus.Registerer, cache cache.Cache, exchangeClient authnlib.TokenExchanger, - folderAPIURL string, + cfg RBACServerSettings, ) { var folderStore store.FolderStore // FIXME: for now we default to using database read proxy for folders if the api url is not configured. // we should remove this and the sql implementation once we have verified that is works correctly - if folderAPIURL == "" { + if cfg.Folder.Host == "" { folderStore = store.NewSQLFolderStore(db, tracer) } else { folderStore = store.NewAPIFolderStore(tracer, func(ctx context.Context) (*rest.Config, error) { return &rest.Config{ - Host: folderAPIURL, + Host: cfg.Folder.Host, WrapTransport: func(rt http.RoundTripper) http.RoundTripper { return &tokenExhangeRoundTripper{te: exchangeClient, rt: rt} }, + TLSClientConfig: rest.TLSClientConfig{ + Insecure: cfg.Folder.Insecure, + CAFile: cfg.Folder.CAFile, + }, QPS: 50, Burst: 100, }, nil diff --git a/pkg/services/authz/rbac_settings.go b/pkg/services/authz/rbac_settings.go index 0ee661c2b50..9d643e73af5 100644 --- a/pkg/services/authz/rbac_settings.go +++ b/pkg/services/authz/rbac_settings.go @@ -57,3 +57,16 @@ func readAuthzClientSettings(cfg *setting.Cfg) (*authzClientSettings, error) { return s, nil } + +type RBACServerSettings struct { + Folder FolderAPISettings +} + +type FolderAPISettings struct { + // Host is hostname for folder api + Host string + // Insecure will skip verification of ceritificates. Should only be used for testing + Insecure bool + // CAFile is a filepath to trusted root certificates for server + CAFile string +} diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go index a612113f87a..6ea80687ab7 100644 --- a/pkg/services/featuremgmt/registry.go +++ b/pkg/services/featuremgmt/registry.go @@ -1789,6 +1789,15 @@ var ( HideFromAdminPage: true, HideFromDocs: true, }, + { + Name: "rendererDisableAppPluginsPreload", + Description: "Disable pre-loading app plugins when the request is coming from the renderer", + Stage: FeatureStageExperimental, + Owner: grafanaSharingSquad, + HideFromAdminPage: true, + HideFromDocs: true, + FrontendOnly: true, + }, } ) diff --git a/pkg/services/featuremgmt/toggles_gen.csv b/pkg/services/featuremgmt/toggles_gen.csv index 159071fd378..1a74645d2a3 100644 --- a/pkg/services/featuremgmt/toggles_gen.csv +++ b/pkg/services/featuremgmt/toggles_gen.csv @@ -237,3 +237,4 @@ pluginsCDNSyncLoader,experimental,@grafana/plugins-platform-backend,false,false, alertingJiraIntegration,experimental,@grafana/alerting-squad,false,false,true alertingRuleVersionHistoryRestore,experimental,@grafana/alerting-squad,false,false,true newShareReportDrawer,experimental,@grafana/sharing-squad,false,false,false +rendererDisableAppPluginsPreload,experimental,@grafana/sharing-squad,false,false,true diff --git a/pkg/services/featuremgmt/toggles_gen.go b/pkg/services/featuremgmt/toggles_gen.go index 79eaf5a3a11..043d9446a3a 100644 --- a/pkg/services/featuremgmt/toggles_gen.go +++ b/pkg/services/featuremgmt/toggles_gen.go @@ -958,4 +958,8 @@ const ( // FlagNewShareReportDrawer // Enables the report creation drawer in a dashboard FlagNewShareReportDrawer = "newShareReportDrawer" + + // FlagRendererDisableAppPluginsPreload + // Disable pre-loading app plugins when the request is coming from the renderer + FlagRendererDisableAppPluginsPreload = "rendererDisableAppPluginsPreload" ) diff --git a/pkg/services/featuremgmt/toggles_gen.json b/pkg/services/featuremgmt/toggles_gen.json index bf878a38563..67a16387684 100644 --- a/pkg/services/featuremgmt/toggles_gen.json +++ b/pkg/services/featuremgmt/toggles_gen.json @@ -3593,6 +3593,21 @@ "hideFromAdminPage": true } }, + { + "metadata": { + "name": "rendererDisableAppPluginsPreload", + "resourceVersion": "1740386710764", + "creationTimestamp": "2025-02-24T08:45:10Z" + }, + "spec": { + "description": "Disable pre-loading app plugins when the request is coming from the renderer", + "stage": "experimental", + "codeowner": "@grafana/sharing-squad", + "frontend": true, + "hideFromAdminPage": true, + "hideFromDocs": true + } + }, { "metadata": { "name": "reportingRetries", diff --git a/pkg/services/ngalert/api/compat_contact_points.go b/pkg/services/ngalert/api/compat_contact_points.go index d10c3859598..1299af0bb64 100644 --- a/pkg/services/ngalert/api/compat_contact_points.go +++ b/pkg/services/ngalert/api/compat_contact_points.go @@ -91,6 +91,13 @@ func ContactPointToContactPointExport(cp definitions.ContactPoint) (notify.APIRe } integration = append(integration, el) } + for _, i := range cp.Jira { + el, err := marshallIntegration(j, "jira", i, i.DisableResolveMessage) + if err != nil { + errs = append(errs, err) + } + integration = append(integration, el) + } for _, i := range cp.Kafka { el, err := marshallIntegration(j, "kafka", i, i.DisableResolveMessage) if err != nil { @@ -271,6 +278,11 @@ func parseIntegration(json jsoniter.API, result *definitions.ContactPoint, recei if err = json.Unmarshal(data, &integration); err == nil { result.Googlechat = append(result.Googlechat, integration) } + case "jira": + integration := definitions.JiraIntegration{DisableResolveMessage: disable} + if err = json.Unmarshal(data, &integration); err == nil { + result.Jira = append(result.Jira, integration) + } case "kafka": integration := definitions.KafkaIntegration{DisableResolveMessage: disable} if err = json.Unmarshal(data, &integration); err == nil { diff --git a/pkg/services/ngalert/api/tooling/definitions/contact_points.go b/pkg/services/ngalert/api/tooling/definitions/contact_points.go index 9df9b8ee444..498ac6f0d37 100644 --- a/pkg/services/ngalert/api/tooling/definitions/contact_points.go +++ b/pkg/services/ngalert/api/tooling/definitions/contact_points.go @@ -62,6 +62,29 @@ type GooglechatIntegration struct { Message *string `json:"message,omitempty" yaml:"message,omitempty" hcl:"message"` } +type JiraIntegration struct { + DisableResolveMessage *bool `json:"-" yaml:"-" hcl:"disable_resolve_message"` + + URL string `yaml:"api_url,omitempty" json:"api_url,omitempty" hcl:"api_url"` + Project string `yaml:"project,omitempty" json:"project,omitempty" hcl:"project"` + IssueType string `yaml:"issue_type,omitempty" json:"issue_type,omitempty" hcl:"issue_type"` + + Summary *string `yaml:"summary,omitempty" json:"summary,omitempty" hcl:"summary"` + Description *string `yaml:"description,omitempty" json:"description,omitempty" hcl:"description"` + Labels *[]string `yaml:"labels,omitempty" json:"labels,omitempty" hcl:"labels"` + Priority *string `yaml:"priority,omitempty" json:"priority,omitempty" hcl:"priority"` + ReopenTransition *string `yaml:"reopen_transition,omitempty" json:"reopen_transition,omitempty" hcl:"reopen_transition"` + ResolveTransition *string `yaml:"resolve_transition,omitempty" json:"resolve_transition,omitempty" hcl:"resolve_transition"` + WontFixResolution *string `yaml:"wont_fix_resolution,omitempty" json:"wont_fix_resolution,omitempty" hcl:"wont_fix_resolution"` + ReopenDuration *string `yaml:"reopen_duration,omitempty" json:"reopen_duration,omitempty" hcl:"reopen_duration"` + DedupKeyFieldName *string `yaml:"dedup_key_field,omitempty" json:"dedup_key_field,omitempty" hcl:"dedup_key_field"` + Fields *map[string]any `yaml:"fields,omitempty" json:"fields,omitempty" hcl:"fields"` + + User *Secret `yaml:"user,omitempty" json:"user,omitempty" hcl:"user"` + Password *Secret `yaml:"password,omitempty" json:"password,omitempty" hcl:"password"` + Token *Secret `yaml:"api_token,omitempty" json:"api_token,omitempty" hcl:"api_token"` +} + type KafkaIntegration struct { DisableResolveMessage *bool `json:"-" yaml:"-" hcl:"disable_resolve_message"` @@ -321,6 +344,7 @@ type ContactPoint struct { Discord []DiscordIntegration `json:"discord" yaml:"discord" hcl:"discord,block"` Email []EmailIntegration `json:"email" yaml:"email" hcl:"email,block"` Googlechat []GooglechatIntegration `json:"googlechat" yaml:"googlechat" hcl:"googlechat,block"` + Jira []JiraIntegration `json:"jira" yaml:"jira" hcl:"jira,block"` Kafka []KafkaIntegration `json:"kafka" yaml:"kafka" hcl:"kafka,block"` Line []LineIntegration `json:"line" yaml:"line" hcl:"line,block"` Mqtt []MqttIntegration `json:"mqtt" yaml:"mqtt" hcl:"mqtt,block"` diff --git a/pkg/services/ngalert/notifier/channels_config/available_channels.go b/pkg/services/ngalert/notifier/channels_config/available_channels.go index e1748a7550b..a64c641a40e 100644 --- a/pkg/services/ngalert/notifier/channels_config/available_channels.go +++ b/pkg/services/ngalert/notifier/channels_config/available_channels.go @@ -5,6 +5,7 @@ import ( "os" "strings" + "github.com/grafana/alerting/receivers/jira" alertingMqtt "github.com/grafana/alerting/receivers/mqtt" alertingOpsgenie "github.com/grafana/alerting/receivers/opsgenie" alertingPagerduty "github.com/grafana/alerting/receivers/pagerduty" @@ -365,7 +366,7 @@ func GetAvailableNotifiers() []*NotifierPlugin { InputType: InputTypeText, PropertyName: "details", }, - { //New in 11.1 + { // New in 11.1 Label: "URL", Description: "The URL to send API requests to", Element: ElementTypeInput, @@ -1708,6 +1709,154 @@ func GetAvailableNotifiers() []*NotifierPlugin { }, }, }, + { // Since Grafana 11.6 + Type: "jira", + Name: "Jira", + Description: "Creates Jira issues from alerts", + Heading: "Jira settings", + Options: []NotifierOption{ + { + Label: "API URL of Jira instance, including version of API", + Element: ElementTypeInput, + InputType: InputTypeText, + Placeholder: "https://grafana.atlassian.net/rest/api/3", + PropertyName: "api_url", + Description: "Supported v2 or v3 APIs", + Required: true, + }, + { + Label: "HTTP Basic Authentication - Username", + Element: ElementTypeInput, + InputType: InputTypeText, + PropertyName: "user", + Description: "Username to use for Jira authentication.", + Secure: true, + Required: false, + }, + { + Label: "HTTP Basic Authentication - Password", + Element: ElementTypeInput, + InputType: InputTypePassword, + PropertyName: "password", + // Go to https://id.atlassian.com/manage-profile/security/api-tokens to obtain a token. + Description: "Password to use for Jira authentication.", + Secure: true, + Required: false, + }, + { + Label: "Authorization Header - Personal Access Token", + Element: ElementTypeInput, + InputType: InputTypePassword, + PropertyName: "api_token", + // Go to https://confluence.atlassian.com/enterprise/using-personal-access-tokens-1026032365.html for how to obtain a token. + Description: "Personal Access Token that is used as a bearer authorization header.", + Secure: true, + Required: false, + }, + { + Label: "Project Key", + Description: "The project key associated with the relevant Jira project", + Element: ElementTypeInput, + InputType: InputTypeText, + Placeholder: "Grafana", + PropertyName: "project", + Required: true, + }, + { + Label: "Issue Type", + Description: "The type of the Jira issue (e.g., Bug, Task, Story). You can use templates to customize this field.", + Element: ElementTypeInput, + InputType: InputTypeText, + Placeholder: "Task", + Required: true, + PropertyName: "issue_type", + }, + { + Label: "Summary", + Description: fmt.Sprintf("The summary of the Jira issue. You can use templates to customize this field. Maximum length is %d characters.", jira.MaxSummaryLenRunes), + Element: ElementTypeInput, + InputType: InputTypeText, + Placeholder: jira.DefaultSummary, + PropertyName: "summary", + }, + { + Label: "Description", + Description: fmt.Sprintf("The description of the Jira issue. You can use templates to customize this field. Maximum length is %d characters.", jira.MaxDescriptionLenRunes), + Element: ElementTypeTextArea, + InputType: InputTypeText, + Placeholder: jira.DefaultDescription, + PropertyName: "description", + }, + { + Label: "Labels", + Description: "Labels to assign to the Jira issue. You can use templates to customize this field.", + Element: ElementStringArray, + Placeholder: "", + PropertyName: "labels", + }, + { + Label: "Priority", + Description: "The priority of the Jira issue (e.g., High, Medium, Low). You can use templates to customize this field.", + Element: ElementTypeInput, + InputType: InputTypeText, + Placeholder: jira.DefaultPriority, + PropertyName: "priority", + Required: false, + }, + { + Label: "Resolve Transition", + Description: `Name of the workflow transition to resolve an issue. The target status must have the category "done". If not set, the issue will not be resolved.`, + Element: ElementTypeInput, + InputType: InputTypeText, + Placeholder: "", + PropertyName: "resolve_transition", + Required: false, + }, + { + Label: "Reopen Transition", + Description: `Name of the workflow transition to resolve an issue. The target status must not have the category "done". If not set, the issue will not be reopened.`, + Element: ElementTypeInput, + InputType: InputTypeText, + Placeholder: "", + PropertyName: "reopen_transition", + Required: false, + }, + { + Label: "Reopen Duration", + Description: "Reopen the issue when it is not older than this value in minutes. Otherwise, create a new issue.", + Element: ElementTypeInput, + InputType: InputTypeText, + Placeholder: "10m", + PropertyName: "reopen_duration", + }, + { + Label: "\"Won't fix\" Transition", + Description: `If reopen transition is defined, ignore issues with that resolution.`, + Element: ElementTypeInput, + InputType: InputTypeText, + Placeholder: "", + PropertyName: "wont_fix_resolution", + Required: false, + }, + { + Label: "Custom field ID for deduplication", + Description: "Id of the custom field where the deduplication key should be stored. Otherwise, it is added to labels in format 'ALERT($KEY).'", + Element: ElementTypeInput, + InputType: InputTypeText, + Placeholder: "10000", + ValidationRule: "^[0-9]+$", + PropertyName: "dedup_key_field", + }, + { + Label: "Custom Field Data", + Description: "Custom field data to set on the Jira issue.", + Element: ElementTypeKeyValueMap, + InputType: InputTypeText, + Placeholder: "", + PropertyName: "fields", + }, + }, + }, } } diff --git a/pkg/services/ngalert/notifier/channels_config/available_channels_test.go b/pkg/services/ngalert/notifier/channels_config/available_channels_test.go index 5e305cb1224..cc2defa2c80 100644 --- a/pkg/services/ngalert/notifier/channels_config/available_channels_test.go +++ b/pkg/services/ngalert/notifier/channels_config/available_channels_test.go @@ -27,20 +27,38 @@ func TestGetSecretKeysForContactPointType(t *testing.T) { {receiverType: "prometheus-alertmanager", expectedSecretFields: []string{"basicAuthPassword"}}, {receiverType: "discord", expectedSecretFields: []string{"url"}}, {receiverType: "googlechat", expectedSecretFields: []string{"url"}}, - {receiverType: "line", expectedSecretFields: []string{"token"}}, + {receiverType: "LINE", expectedSecretFields: []string{"token"}}, {receiverType: "threema", expectedSecretFields: []string{"api_secret"}}, {receiverType: "opsgenie", expectedSecretFields: []string{"apiKey"}}, {receiverType: "webex", expectedSecretFields: []string{"bot_token"}}, {receiverType: "sns", expectedSecretFields: []string{"sigv4.access_key", "sigv4.secret_key"}}, + {receiverType: "mqtt", expectedSecretFields: []string{"password", "tlsConfig.caCertificate", "tlsConfig.clientCertificate", "tlsConfig.clientKey"}}, + {receiverType: "jira", expectedSecretFields: []string{"user", "password", "api_token"}}, } + n := GetAvailableNotifiers() + allTypes := make(map[string]struct{}, len(n)) + for _, plugin := range n { + allTypes[plugin.Type] = struct{}{} + } + for _, testCase := range testCases { + delete(allTypes, testCase.receiverType) t.Run(testCase.receiverType, func(t *testing.T) { got, err := GetSecretKeysForContactPointType(testCase.receiverType) require.NoError(t, err) - t.Logf("got secret fields: %#v", got) require.ElementsMatch(t, testCase.expectedSecretFields, got) }) } + + for integrationType := range allTypes { + t.Run(integrationType, func(t *testing.T) { + got, err := GetSecretKeysForContactPointType(integrationType) + require.NoError(t, err) + require.Emptyf(t, got, "secret keys for %s should be empty", integrationType) + }) + } + + require.Emptyf(t, allTypes, "not all types are covered: %s", allTypes) } func Test_getSecretFields(t *testing.T) { diff --git a/pkg/services/ngalert/notifier/channels_config/plugin.go b/pkg/services/ngalert/notifier/channels_config/plugin.go index f390ee1d9fc..5a8b7527604 100644 --- a/pkg/services/ngalert/notifier/channels_config/plugin.go +++ b/pkg/services/ngalert/notifier/channels_config/plugin.go @@ -45,6 +45,8 @@ const ( ElementTypeSubform = "subform" // ElementSubformArray will render a multiple sub-forms with schema defined in SubformOptions ElementSubformArray = "subform_array" + // ElementStringArray will render a set of fields to manage an array of strings. + ElementStringArray = "string_array" ) // InputType is the type of input that can be rendered in the frontend. diff --git a/pkg/services/ngalert/prom/convert.go b/pkg/services/ngalert/prom/convert.go index d14a37aa9f5..bb9d4c3d616 100644 --- a/pkg/services/ngalert/prom/convert.go +++ b/pkg/services/ngalert/prom/convert.go @@ -1,16 +1,31 @@ package prom import ( - "encoding/json" "fmt" "time" + "github.com/google/uuid" "gopkg.in/yaml.v3" "github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/ngalert/models" + "github.com/grafana/grafana/pkg/util" ) +const ( + // ruleUIDLabel is a special label that can be used to set a custom UID for a Prometheus + // alert rule when converting it to a Grafana alert rule. If this label is not present, + // a stable UID will be generated automatically based on the rule's data. + ruleUIDLabel = "__grafana_alert_rule_uid__" +) + +const ( + queryRefID = "query" + prometheusMathRefID = "prometheus_math" + thresholdRefID = "threshold" +) + +// Config defines the configuration options for the Prometheus to Grafana rules converter. type Config struct { DatasourceUID string DatasourceType string @@ -22,6 +37,7 @@ type Config struct { AlertRules RulesConfig } +// RulesConfig contains configuration that applies to either recording or alerting rules. type RulesConfig struct { IsPaused bool } @@ -34,7 +50,7 @@ var ( FromTimeRange: &defaultTimeRange, EvaluationOffset: &defaultEvaluationOffset, ExecErrState: models.ErrorErrState, - NoDataState: models.NoData, + NoDataState: models.OK, } ) @@ -42,6 +58,9 @@ type Converter struct { cfg Config } +// NewConverter creates a new Converter instance with the provided configuration. +// It validates the configuration and returns an error if any required fields are missing +// or if the configuration is invalid. func NewConverter(cfg Config) (*Converter, error) { if cfg.DatasourceUID == "" { return nil, fmt.Errorf("datasource UID is required") @@ -114,6 +133,12 @@ func (p *Converter) convertRuleGroup(orgID int64, namespaceUID string, promGroup gr.Title = fmt.Sprintf("%s (%d)", gr.Title, val) } + uid, err := getUID(orgID, namespaceUID, promGroup.Name, i, rule) + if err != nil { + return nil, fmt.Errorf("failed to generate UID for rule '%s': %w", gr.Title, err) + } + gr.UID = uid + rules = append(rules, gr) } @@ -127,21 +152,52 @@ func (p *Converter) convertRuleGroup(orgID int64, namespaceUID string, promGroup return result, nil } +// getUID returns a UID for a Prometheus rule. +// If the rule has a special label its value is used. +// Otherwise, a stable UUID is generated by using a hash of the rule's data. +func getUID(orgID int64, namespaceUID string, group string, position int, promRule PrometheusRule) (string, error) { + if uid, ok := promRule.Labels[ruleUIDLabel]; ok { + if err := util.ValidateUID(uid); err != nil { + return "", fmt.Errorf("invalid UID label value: %s; %w", uid, err) + } + return uid, nil + } + + // Generate stable UUID based on the orgID, namespace, group and position. + uidData := fmt.Sprintf("%d|%s|%s|%d", orgID, namespaceUID, group, position) + u := uuid.NewSHA1(uuid.NameSpaceOID, []byte(uidData)) + + return u.String(), nil +} + func (p *Converter) convertRule(orgID int64, namespaceUID, group string, rule PrometheusRule) (models.AlertRule, error) { var forInterval time.Duration if rule.For != nil { forInterval = time.Duration(*rule.For) } - queryNode, err := createAlertQueryNode(p.cfg.DatasourceUID, p.cfg.DatasourceType, rule.Expr, *p.cfg.FromTimeRange, *p.cfg.EvaluationOffset) + var query []models.AlertQuery + var title string + var isPaused bool + var record *models.Record + var err error + + isRecordingRule := rule.Record != "" + query, err = p.createQuery(rule.Expr, isRecordingRule) if err != nil { return models.AlertRule{}, err } - var title string - if rule.Record != "" { + if isRecordingRule { + record = &models.Record{ + From: queryRefID, + Metric: rule.Record, + } + + isPaused = p.cfg.RecordingRules.IsPaused title = rule.Record } else { + isPaused = p.cfg.AlertRules.IsPaused title = rule.Alert } @@ -159,14 +215,16 @@ func (p *Converter) convertRule(orgID int64, namespaceUID, group string, rule Pr OrgID: orgID, NamespaceUID: namespaceUID, Title: title, - Data: []models.AlertQuery{queryNode}, - Condition: "A", + Data: query, + Condition: query[len(query)-1].RefID, NoDataState: p.cfg.NoDataState, ExecErrState: p.cfg.ExecErrState, Annotations: rule.Annotations, Labels: labels, For: forInterval, RuleGroup: group, + IsPaused: isPaused, + Record: record, Metadata: models.AlertRuleMetadata{ PrometheusStyleRule: &models.PrometheusStyleRule{ OriginalRuleDefinition: string(originalRuleDefinition), @@ -174,47 +232,41 @@ func (p *Converter) convertRule(orgID int64, namespaceUID, group string, rule Pr }, } - if rule.Record != "" { - result.Record = &models.Record{ - From: "A", - Metric: rule.Record, - } - result.IsPaused = p.cfg.RecordingRules.IsPaused - } else { - result.IsPaused = p.cfg.AlertRules.IsPaused - } - return result, nil } -func createAlertQueryNode(datasourceUID, datasourceType, expr string, fromTimeRange, evaluationOffset time.Duration) (models.AlertQuery, error) { - modelData := map[string]interface{}{ - "datasource": map[string]interface{}{ - "type": datasourceType, - "uid": datasourceUID, - }, - "expr": expr, - "instant": true, - "range": false, - "refId": "A", - } - - if datasourceType == datasources.DS_LOKI { - modelData["queryType"] = "instant" - } - - modelJSON, err := json.Marshal(modelData) +// createQuery constructs the alert query nodes for a given Prometheus rule expression. +// It returns a slice of AlertQuery that represent the evaluation steps for the rule. +// +// For recording rules it generates a single query node that +// executes the PromQL query in the configured datasource. +// +// For alerting rules, it generates three query nodes: +// 1. Query Node (query): Executes the PromQL query using the configured datasource. +// 2. Math Node (prometheus_math): Applies a math expression "is_number($query) || is_nan($query) || is_inf($query)". +// 3. Threshold Node (threshold): Gets the result from the math node and checks that it's greater than 0. +// +// This is needed to ensure that we keep the Prometheus behaviour, where any returned result +// is considered alerting, and only when the query returns no data is the alert treated as normal. +func (p *Converter) createQuery(expr string, isRecordingRule bool) ([]models.AlertQuery, error) { + queryNode, err := createQueryNode(p.cfg.DatasourceUID, p.cfg.DatasourceType, expr, *p.cfg.FromTimeRange, *p.cfg.EvaluationOffset) if err != nil { - return models.AlertQuery{}, err + return nil, err } - return models.AlertQuery{ - DatasourceUID: datasourceUID, - Model: modelJSON, - RefID: "A", - RelativeTimeRange: models.RelativeTimeRange{ - From: models.Duration(fromTimeRange + evaluationOffset), - To: models.Duration(0 + evaluationOffset), - }, - }, nil + if isRecordingRule { + return []models.AlertQuery{queryNode}, nil + } + + mathNode, err := createMathNode() + if err != nil { + return nil, err + } + + thresholdNode, err := createThresholdNode() + if err != nil { + return nil, err + } + + return []models.AlertQuery{queryNode, mathNode, thresholdNode}, nil } diff --git a/pkg/services/ngalert/prom/convert_test.go b/pkg/services/ngalert/prom/convert_test.go index f175686fd3d..3bad4795fcb 100644 --- a/pkg/services/ngalert/prom/convert_test.go +++ b/pkg/services/ngalert/prom/convert_test.go @@ -1,15 +1,21 @@ package prom import ( + "encoding/json" + "fmt" "testing" "time" + "github.com/google/uuid" prommodel "github.com/prometheus/common/model" "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" + "github.com/grafana/grafana/pkg/expr" + "github.com/grafana/grafana/pkg/expr/mathexp" "github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/ngalert/models" + "github.com/grafana/grafana/pkg/util" ) func TestPrometheusRulesToGrafana(t *testing.T) { @@ -121,6 +127,9 @@ func TestPrometheusRulesToGrafana(t *testing.T) { if promRule.Record != "" { require.Equal(t, promRule.Record, grafanaRule.Title) + require.NotNil(t, grafanaRule.Record) + require.Equal(t, grafanaRule.Record.From, queryRefID) + require.Equal(t, promRule.Record, grafanaRule.Record.Metric) } else { require.Equal(t, promRule.Alert, grafanaRule.Title) } @@ -136,6 +145,10 @@ func TestPrometheusRulesToGrafana(t *testing.T) { expectedLabels[k] = v } + uidData := fmt.Sprintf("%d|%s|%s|%d", tc.orgID, tc.namespace, tc.promGroup.Name, j) + u := uuid.NewSHA1(uuid.NameSpaceOID, []byte(uidData)) + require.Equal(t, u.String(), grafanaRule.UID, tc.name) + require.Equal(t, expectedLabels, grafanaRule.Labels, tc.name) require.Equal(t, promRule.Annotations, grafanaRule.Annotations, tc.name) require.Equal(t, models.Duration(0*time.Minute), grafanaRule.Data[0].RelativeTimeRange.To) @@ -190,3 +203,221 @@ func TestPrometheusRulesToGrafanaWithDuplicateRuleNames(t *testing.T) { require.Equal(t, "another alert", group.Rules[2].Title) require.Equal(t, "alert (3)", group.Rules[3].Title) } + +func TestCreateMathNode(t *testing.T) { + node, err := createMathNode() + require.NoError(t, err) + + require.Equal(t, expr.DatasourceUID, node.DatasourceUID) + require.Equal(t, string(expr.QueryTypeMath), node.QueryType) + require.Equal(t, "prometheus_math", node.RefID) + + var model map[string]interface{} + err = json.Unmarshal(node.Model, &model) + require.NoError(t, err) + + require.Equal(t, "prometheus_math", model["refId"]) + require.Equal(t, string(expr.QueryTypeMath), model["type"]) + require.Equal(t, "is_number($query) || is_nan($query) || is_inf($query)", model["expression"]) + + ds := model["datasource"].(map[string]interface{}) + require.Equal(t, expr.DatasourceUID, ds["name"]) + require.Equal(t, expr.DatasourceType, ds["type"]) + require.Equal(t, expr.DatasourceUID, ds["uid"]) +} + +func TestCreateThresholdNode(t *testing.T) { + node, err := createThresholdNode() + require.NoError(t, err) + + require.Equal(t, expr.DatasourceUID, node.DatasourceUID) + require.Equal(t, string(expr.QueryTypeThreshold), node.QueryType) + require.Equal(t, "threshold", node.RefID) + + var model map[string]interface{} + err = json.Unmarshal(node.Model, &model) + require.NoError(t, err) + + require.Equal(t, "threshold", model["refId"]) + require.Equal(t, string(expr.QueryTypeThreshold), model["type"]) + + ds := model["datasource"].(map[string]interface{}) + require.Equal(t, expr.DatasourceUID, ds["name"]) + require.Equal(t, expr.DatasourceType, ds["type"]) + require.Equal(t, expr.DatasourceUID, ds["uid"]) + + conditions := model["conditions"].([]interface{}) + require.Len(t, conditions, 1) + + condition := conditions[0].(map[string]interface{}) + evaluator := condition["evaluator"].(map[string]interface{}) + require.Equal(t, string(expr.ThresholdIsAbove), evaluator["type"]) + require.Equal(t, []interface{}{float64(0)}, evaluator["params"]) +} + +func TestPrometheusRulesToGrafana_NodesInRules(t *testing.T) { + cfg := Config{ + DatasourceUID: "datasource-uid", + DatasourceType: datasources.DS_PROMETHEUS, + } + converter, err := NewConverter(cfg) + require.NoError(t, err) + + t.Run("alert rule should have math and threshold nodes", func(t *testing.T) { + group := PrometheusRuleGroup{ + Name: "test", + Rules: []PrometheusRule{ + { + Alert: "alert1", + Expr: "up == 0", + }, + }, + } + + result, err := converter.PrometheusRulesToGrafana(1, "namespace", group) + require.NoError(t, err) + require.Len(t, result.Rules, 1) + require.Len(t, result.Rules[0].Data, 3) + + // First node should be query + require.Equal(t, "query", result.Rules[0].Data[0].RefID) + + // Second node should be math + require.Equal(t, "prometheus_math", result.Rules[0].Data[1].RefID) + require.Equal(t, string(expr.QueryTypeMath), result.Rules[0].Data[1].QueryType) + // Check that the math expression is valid + var model map[string]interface{} + err = json.Unmarshal(result.Rules[0].Data[1].Model, &model) + require.NoError(t, err) + require.Equal(t, "is_number($query) || is_nan($query) || is_inf($query)", model["expression"]) + // The math expression should be parsed successfully + _, err = mathexp.New(model["expression"].(string)) + require.NoError(t, err) + + // Third node should be threshold + require.Equal(t, "threshold", result.Rules[0].Data[2].RefID) + require.Equal(t, string(expr.QueryTypeThreshold), result.Rules[0].Data[2].QueryType) + }) + + t.Run("recording rule should only have query node", func(t *testing.T) { + group := PrometheusRuleGroup{ + Name: "test", + Rules: []PrometheusRule{ + { + Record: "metric", + Expr: "sum(rate(http_requests_total[5m]))", + }, + }, + } + + result, err := converter.PrometheusRulesToGrafana(1, "namespace", group) + require.NoError(t, err) + require.Len(t, result.Rules, 1) + require.Len(t, result.Rules[0].Data, 1) + + // Should only have query node + require.Equal(t, "query", result.Rules[0].Data[0].RefID) + }) +} + +func TestPrometheusRulesToGrafana_UID(t *testing.T) { + orgID := int64(1) + namespace := "some-namespace" + + promGroup := PrometheusRuleGroup{ + Name: "test-group-1", + Interval: prommodel.Duration(10 * time.Second), + Rules: []PrometheusRule{ + { + Alert: "alert-1", + Expr: "cpu_usage > 80", + For: util.Pointer(prommodel.Duration(5 * time.Minute)), + Labels: map[string]string{ + "severity": "critical", + ruleUIDLabel: "rule-uid-1", + }, + Annotations: map[string]string{ + "summary": "CPU usage is critical", + }, + }, + }, + } + + converter, err := NewConverter(Config{ + DatasourceUID: "datasource-uid", + DatasourceType: datasources.DS_PROMETHEUS, + }) + require.NoError(t, err) + + t.Run("if not specified, UID is generated based on the rule index", func(t *testing.T) { + grafanaGroup, err := converter.PrometheusRulesToGrafana(orgID, namespace, promGroup) + require.NoError(t, err) + + firstUID := grafanaGroup.Rules[0].UID + + // Convert again + grafanaGroup, err = converter.PrometheusRulesToGrafana(orgID, namespace, promGroup) + require.NoError(t, err) + + secondUID := grafanaGroup.Rules[0].UID + + // They must be equal + require.NotEmpty(t, firstUID) + require.Equal(t, firstUID, secondUID) + }) + + t.Run("if the special label is specified", func(t *testing.T) { + t.Run("and the label is valid it should be used", func(t *testing.T) { + orgID := int64(1) + namespace := "some-namespace" + + converter, err := NewConverter(Config{ + DatasourceUID: "datasource-uid", + DatasourceType: datasources.DS_PROMETHEUS, + }) + require.NoError(t, err) + + promGroup.Rules[0].Labels[ruleUIDLabel] = "rule-uid-1" + + grafanaGroup, err := converter.PrometheusRulesToGrafana(orgID, namespace, promGroup) + require.NoError(t, err) + + require.Equal(t, "rule-uid-1", grafanaGroup.Rules[0].UID) + }) + + t.Run("and the label is invalid", func(t *testing.T) { + orgID := int64(1) + namespace := "some-namespace" + + converter, err := NewConverter(Config{ + DatasourceUID: "datasource-uid", + DatasourceType: datasources.DS_PROMETHEUS, + }) + require.NoError(t, err) + + // create a string of 50 characters + promGroup.Rules[0].Labels[ruleUIDLabel] = "aaaabbbbccccddddeeeeffffgggghhhhiiiijjjjkkkkllllmm" // too long + + grafanaGroup, err := converter.PrometheusRulesToGrafana(orgID, namespace, promGroup) + require.Errorf(t, err, "invalid UID label value") + require.Nil(t, grafanaGroup) + }) + + t.Run("and the label is empty", func(t *testing.T) { + orgID := int64(1) + namespace := "some-namespace" + + converter, err := NewConverter(Config{ + DatasourceUID: "datasource-uid", + DatasourceType: datasources.DS_PROMETHEUS, + }) + require.NoError(t, err) + + promGroup.Rules[0].Labels[ruleUIDLabel] = "" + + grafanaGroup, err := converter.PrometheusRulesToGrafana(orgID, namespace, promGroup) + require.Errorf(t, err, "invalid UID label value") + require.Nil(t, grafanaGroup) + }) + }) +} diff --git a/pkg/services/ngalert/prom/query.go b/pkg/services/ngalert/prom/query.go new file mode 100644 index 00000000000..74aed34f83f --- /dev/null +++ b/pkg/services/ngalert/prom/query.go @@ -0,0 +1,127 @@ +package prom + +import ( + "encoding/json" + "fmt" + "time" + + "github.com/grafana/grafana/pkg/expr" + "github.com/grafana/grafana/pkg/services/datasources" + "github.com/grafana/grafana/pkg/services/ngalert/models" +) + +type CommonQueryModel struct { + Datasource datasources.DataSource `json:"datasource"` + RefID string `json:"refId"` + Type expr.QueryType `json:"type"` +} + +func createQueryNode(datasourceUID, datasourceType, expr string, fromTimeRange, evaluationOffset time.Duration) (models.AlertQuery, error) { + modelData := map[string]interface{}{ + "datasource": map[string]interface{}{ + "type": datasourceType, + "uid": datasourceUID, + }, + "expr": expr, + "instant": true, + "range": false, + "refId": queryRefID, + } + + if datasourceType == datasources.DS_LOKI { + modelData["queryType"] = "instant" + } + + modelJSON, err := json.Marshal(modelData) + if err != nil { + return models.AlertQuery{}, err + } + + return models.AlertQuery{ + DatasourceUID: datasourceUID, + Model: modelJSON, + RefID: queryRefID, + RelativeTimeRange: models.RelativeTimeRange{ + From: models.Duration(fromTimeRange + evaluationOffset), + To: models.Duration(0 + evaluationOffset), + }, + }, nil +} + +type MathQueryModel struct { + expr.MathQuery + CommonQueryModel +} + +func createMathNode() (models.AlertQuery, error) { + ds, err := expr.DataSourceModelFromNodeType(expr.TypeCMDNode) + if err != nil { + return models.AlertQuery{}, err + } + + model := MathQueryModel{ + CommonQueryModel: CommonQueryModel{ + Datasource: *ds, + RefID: prometheusMathRefID, + Type: expr.QueryTypeMath, + }, + MathQuery: expr.MathQuery{ + Expression: fmt.Sprintf("is_number($%[1]s) || is_nan($%[1]s) || is_inf($%[1]s)", queryRefID), + }, + } + + modelJSON, err := json.Marshal(model) + if err != nil { + return models.AlertQuery{}, err + } + + return models.AlertQuery{ + DatasourceUID: expr.DatasourceUID, + Model: modelJSON, + RefID: prometheusMathRefID, + QueryType: string(model.Type), + }, nil +} + +type ThresholdQueryModel struct { + expr.ThresholdQuery + CommonQueryModel +} + +func createThresholdNode() (models.AlertQuery, error) { + ds, err := expr.DataSourceModelFromNodeType(expr.TypeCMDNode) + if err != nil { + return models.AlertQuery{}, err + } + + model := ThresholdQueryModel{ + CommonQueryModel: CommonQueryModel{ + Datasource: *ds, + RefID: thresholdRefID, + Type: expr.QueryTypeThreshold, + }, + ThresholdQuery: expr.ThresholdQuery{ + Expression: prometheusMathRefID, + Conditions: []expr.ThresholdConditionJSON{ + { + Evaluator: expr.ConditionEvalJSON{ + Type: expr.ThresholdIsAbove, + Params: []float64{0}, + }, + }, + }, + }, + } + + modelJSON, err := json.Marshal(model) + if err != nil { + return models.AlertQuery{}, err + } + + return models.AlertQuery{ + DatasourceUID: expr.DatasourceUID, + Model: modelJSON, + RefID: thresholdRefID, + QueryType: string(model.Type), + }, nil +} diff --git a/pkg/services/ngalert/provisioning/contactpoints_test.go b/pkg/services/ngalert/provisioning/contactpoints_test.go index 7a8c5e5bd10..cab8dd42400 100644 --- a/pkg/services/ngalert/provisioning/contactpoints_test.go +++ b/pkg/services/ngalert/provisioning/contactpoints_test.go @@ -423,6 +423,9 @@ func TestRemoveSecretsForContactPoint(t *testing.T) { "webhook": func(settings map[string]any) { // add additional field to the settings because valid config does not allow it to be specified along with password settings["authorization_credentials"] = "test-authz-creds" }, + "jira": func(settings map[string]any) { // add additional field to the settings because valid config does not allow it to be specified along with password + settings["api_token"] = "test-token" + }, } configs := notify.AllKnownConfigsForTesting diff --git a/pkg/services/ngalert/writer/prom.go b/pkg/services/ngalert/writer/prom.go index 9778d2f824b..ff735fecc26 100644 --- a/pkg/services/ngalert/writer/prom.go +++ b/pkg/services/ngalert/writer/prom.go @@ -25,10 +25,11 @@ const backendType = "prometheus" const ( // Fixed error messages - MimirDuplicateTimestampError = "err-mimir-sample-duplicate-timestamp" - MimirInvalidLabelError = "err-mimir-label-invalid" - MimirMaxSeriesPerUserError = "err-mimir-max-series-per-user" - MimirLabelValueTooLongError = "err-mimir-label-value-too-long" + MimirDuplicateTimestampError = "err-mimir-sample-duplicate-timestamp" + MimirInvalidLabelError = "err-mimir-label-invalid" + MimirLabelValueTooLongError = "err-mimir-label-value-too-long" + MimirMaxLabelNamesPerSeriesError = "err-mimir-max-label-names-per-series" + MimirMaxSeriesPerUserError = "err-mimir-max-series-per-user" // Best effort error messages PrometheusDuplicateTimestampError = "duplicate sample for timestamp" @@ -267,16 +268,12 @@ func checkWriteError(writeErr promremote.WriteError) (err error, ignored bool) { } } - if strings.Contains(msg, MimirInvalidLabelError) { - return errors.Join(ErrRejectedWrite, writeErr), false - } - - // this can happen when user exceeded defined maximum of - if strings.Contains(msg, MimirMaxSeriesPerUserError) { - return errors.Join(ErrRejectedWrite, writeErr), false - } - - if strings.Contains(msg, MimirLabelValueTooLongError) { + // Check for expected user errors. + switch { + case strings.Contains(msg, MimirInvalidLabelError), + strings.Contains(msg, MimirMaxSeriesPerUserError), + strings.Contains(msg, MimirMaxLabelNamesPerSeriesError), + strings.Contains(msg, MimirLabelValueTooLongError): return errors.Join(ErrRejectedWrite, writeErr), false } diff --git a/pkg/services/ngalert/writer/prom_test.go b/pkg/services/ngalert/writer/prom_test.go index af5bd5e9f29..c300d700d93 100644 --- a/pkg/services/ngalert/writer/prom_test.go +++ b/pkg/services/ngalert/writer/prom_test.go @@ -240,7 +240,23 @@ func TestPrometheusWriter_Write(t *testing.T) { }) t.Run("too long labels fit under the client error category", func(t *testing.T) { - msg := "received a series whose label value length exceeds the limit, label: 'label-1', value: 'value-1' (truncated) series: 'some_series (err-mimir-label-value-too-long). To adjust the related per-tenant limit, configure -validation.max-length-label-value, or contact your service administrator." + msg := "received a series whose label value length exceeds the limit, label: 'label-1', value: 'value-1' (truncated) series: 'some_series' (err-mimir-label-value-too-long). To adjust the related per-tenant limit, configure -validation.max-length-label-value, or contact your service administrator." + clientErr := testClientWriteError{ + statusCode: http.StatusBadRequest, + msg: &msg, + } + client.writeSeriesFunc = func(ctx context.Context, ts promremote.TSList, opts promremote.WriteOptions) (promremote.WriteResult, promremote.WriteError) { + return promremote.WriteResult{}, clientErr + } + + err := writer.Write(ctx, "test", now, frames, 1, map[string]string{"extra": "label"}) + + require.Error(t, err) + require.ErrorIs(t, err, ErrRejectedWrite) + }) + + t.Run("too many labels fit under the client error category", func(t *testing.T) { + msg := "received a series whose number of labels exceeds the limit (actual: 50, limit: 40) series: 'some_series' (err-mimir-max-label-names-per-series). To adjust the related per-tenant limit, configure -validation.max-label-names-per-series, or contact your service administrator." clientErr := testClientWriteError{ statusCode: http.StatusBadRequest, msg: &msg, diff --git a/pkg/storage/unified/apistore/go.mod b/pkg/storage/unified/apistore/go.mod index d99962d0d35..b7abdb3bb91 100644 --- a/pkg/storage/unified/apistore/go.mod +++ b/pkg/storage/unified/apistore/go.mod @@ -192,7 +192,7 @@ require ( github.com/googleapis/gax-go/v2 v2.14.1 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/websocket v1.5.3 // indirect - github.com/grafana/alerting v0.0.0-20250219153626-c475b1a572b0 // indirect + github.com/grafana/alerting v0.0.0-20250221202230-9d7e00921e44 // indirect github.com/grafana/authlib v0.0.0-20250219100139-6a3b1bbb50e7 // indirect github.com/grafana/dataplane/sdata v0.0.9 // indirect github.com/grafana/dskit v0.0.0-20241105154643-a6b453a88040 // indirect diff --git a/pkg/storage/unified/apistore/go.sum b/pkg/storage/unified/apistore/go.sum index 4d78ed949da..87e7727af96 100644 --- a/pkg/storage/unified/apistore/go.sum +++ b/pkg/storage/unified/apistore/go.sum @@ -566,8 +566,8 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grafana/alerting v0.0.0-20250219153626-c475b1a572b0 h1:LGH+tVzHCDrR9hsltmkP4jmNRg5IreQw5CNFbJKlnts= -github.com/grafana/alerting v0.0.0-20250219153626-c475b1a572b0/go.mod h1:hdGB3dSl8Ma9Rjo2YiAEAjMkZ5HiNJbNDqRKDefRZrM= +github.com/grafana/alerting v0.0.0-20250221202230-9d7e00921e44 h1:vboqvbAO0s0CTALHnqfmNvhCP1ziBcZNpYDbORqvOgg= +github.com/grafana/alerting v0.0.0-20250221202230-9d7e00921e44/go.mod h1:hdGB3dSl8Ma9Rjo2YiAEAjMkZ5HiNJbNDqRKDefRZrM= github.com/grafana/authlib v0.0.0-20250219100139-6a3b1bbb50e7 h1:NTMmow+74I3Jb033xhbRgWQS7A//5TDhiM4tl7bsVP4= github.com/grafana/authlib v0.0.0-20250219100139-6a3b1bbb50e7/go.mod h1:T3X4z0ejGfJOiOmZLFeKCRT/yxWJq/RtclAc/PHj/w4= github.com/grafana/authlib/types v0.0.0-20250219092154-21ce22b49f31 h1:EokLC5grHwLPs4tXW8T6E8187H1e5G9AP0QQ5B60HbA= diff --git a/pkg/storage/unified/resource/go.mod b/pkg/storage/unified/resource/go.mod index 57c54262114..833dd96a890 100644 --- a/pkg/storage/unified/resource/go.mod +++ b/pkg/storage/unified/resource/go.mod @@ -117,7 +117,7 @@ require ( github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect github.com/googleapis/gax-go/v2 v2.14.1 // indirect github.com/gorilla/mux v1.8.1 // indirect - github.com/grafana/alerting v0.0.0-20250219153626-c475b1a572b0 // indirect + github.com/grafana/alerting v0.0.0-20250221202230-9d7e00921e44 // indirect github.com/grafana/dataplane/sdata v0.0.9 // indirect github.com/grafana/grafana-app-sdk/logging v0.30.0 // indirect github.com/grafana/grafana-aws-sdk v0.31.5 // indirect diff --git a/pkg/storage/unified/resource/go.sum b/pkg/storage/unified/resource/go.sum index 9ee7f749839..7d566e2e658 100644 --- a/pkg/storage/unified/resource/go.sum +++ b/pkg/storage/unified/resource/go.sum @@ -397,8 +397,8 @@ github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -github.com/grafana/alerting v0.0.0-20250219153626-c475b1a572b0 h1:LGH+tVzHCDrR9hsltmkP4jmNRg5IreQw5CNFbJKlnts= -github.com/grafana/alerting v0.0.0-20250219153626-c475b1a572b0/go.mod h1:hdGB3dSl8Ma9Rjo2YiAEAjMkZ5HiNJbNDqRKDefRZrM= +github.com/grafana/alerting v0.0.0-20250221202230-9d7e00921e44 h1:vboqvbAO0s0CTALHnqfmNvhCP1ziBcZNpYDbORqvOgg= +github.com/grafana/alerting v0.0.0-20250221202230-9d7e00921e44/go.mod h1:hdGB3dSl8Ma9Rjo2YiAEAjMkZ5HiNJbNDqRKDefRZrM= github.com/grafana/authlib v0.0.0-20250219100139-6a3b1bbb50e7 h1:NTMmow+74I3Jb033xhbRgWQS7A//5TDhiM4tl7bsVP4= github.com/grafana/authlib v0.0.0-20250219100139-6a3b1bbb50e7/go.mod h1:T3X4z0ejGfJOiOmZLFeKCRT/yxWJq/RtclAc/PHj/w4= github.com/grafana/authlib/types v0.0.0-20250219092154-21ce22b49f31 h1:EokLC5grHwLPs4tXW8T6E8187H1e5G9AP0QQ5B60HbA= diff --git a/pkg/tests/apis/alerting/notifications/receivers/receiver_test.go b/pkg/tests/apis/alerting/notifications/receivers/receiver_test.go index 283d996f177..c483b6938ae 100644 --- a/pkg/tests/apis/alerting/notifications/receivers/receiver_test.go +++ b/pkg/tests/apis/alerting/notifications/receivers/receiver_test.go @@ -1392,9 +1392,15 @@ func TestIntegrationCRUD(t *testing.T) { t.Run("should return secrets in secureFields but not settings", func(t *testing.T) { for _, integration := range get.Spec.Integrations { t.Run(integration.Type, func(t *testing.T) { + expected := notify.AllKnownConfigsForTesting[strings.ToLower(integration.Type)] + var fields map[string]any + require.NoError(t, json.Unmarshal([]byte(expected.Config), &fields)) secretFields, err := channels_config.GetSecretKeysForContactPointType(integration.Type) require.NoError(t, err) for _, field := range secretFields { + if _, ok := fields[field]; !ok { // skip field that is not in the original setting + continue + } assert.Contains(t, integration.SecureFields, field) assert.Truef(t, integration.SecureFields[field], "secure field should be always true") diff --git a/pkg/tests/apis/openapi_snapshots/provisioning.grafana.app-v0alpha1.json b/pkg/tests/apis/openapi_snapshots/provisioning.grafana.app-v0alpha1.json index 39e95468748..d573d14730c 100644 --- a/pkg/tests/apis/openapi_snapshots/provisioning.grafana.app-v0alpha1.json +++ b/pkg/tests/apis/openapi_snapshots/provisioning.grafana.app-v0alpha1.json @@ -36,6 +36,380 @@ } } }, + "/apis/provisioning.grafana.app/v0alpha1/jobs": { + "get": { + "tags": [ + "Job" + ], + "description": "list or watch objects of kind Job", + "operationId": "listJobForAllNamespaces", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.JobList" + } + }, + "application/json;stream=watch": { + "schema": { + "$ref": "#/components/schemas/com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.JobList" + } + }, + "application/vnd.kubernetes.protobuf": { + "schema": { + "$ref": "#/components/schemas/com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.JobList" + } + }, + "application/vnd.kubernetes.protobuf;stream=watch": { + "schema": { + "$ref": "#/components/schemas/com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.JobList" + } + }, + "application/yaml": { + "schema": { + "$ref": "#/components/schemas/com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.JobList" + } + } + } + } + }, + "x-kubernetes-action": "list", + "x-kubernetes-group-version-kind": { + "group": "provisioning.grafana.app", + "version": "v0alpha1", + "kind": "Job" + } + }, + "parameters": [ + { + "name": "allowWatchBookmarks", + "in": "query", + "description": "allowWatchBookmarks requests watch events with type \"BOOKMARK\". Servers that do not implement bookmarks may ignore this flag and bookmarks are sent at the server's discretion. Clients should not assume bookmarks are returned at any specific interval, nor may they assume the server will send any BOOKMARK event during a session. If this is not a watch, this field is ignored.", + "schema": { + "type": "boolean", + "uniqueItems": true + } + }, + { + "name": "continue", + "in": "query", + "description": "The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the \"next key\".\n\nThis field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications.", + "schema": { + "type": "string", + "uniqueItems": true + } + }, + { + "name": "fieldSelector", + "in": "query", + "description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.", + "schema": { + "type": "string", + "uniqueItems": true + } + }, + { + "name": "labelSelector", + "in": "query", + "description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + "schema": { + "type": "string", + "uniqueItems": true + } + }, + { + "name": "limit", + "in": "query", + "description": "limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true.\n\nThe server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned.", + "schema": { + "type": "integer", + "uniqueItems": true + } + }, + { + "name": "pretty", + "in": "query", + "description": "If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget).", + "schema": { + "type": "string", + "uniqueItems": true + } + }, + { + "name": "resourceVersion", + "in": "query", + "description": "resourceVersion sets a constraint on what resource versions a request may be served from. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details.\n\nDefaults to unset", + "schema": { + "type": "string", + "uniqueItems": true + } + }, + { + "name": "resourceVersionMatch", + "in": "query", + "description": "resourceVersionMatch determines how resourceVersion is applied to list calls. It is highly recommended that resourceVersionMatch be set for list calls where resourceVersion is set See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details.\n\nDefaults to unset", + "schema": { + "type": "string", + "uniqueItems": true + } + }, + { + "name": "sendInitialEvents", + "in": "query", + "description": "`sendInitialEvents=true` may be set together with `watch=true`. In that case, the watch stream will begin with synthetic events to produce the current state of objects in the collection. Once all such events have been sent, a synthetic \"Bookmark\" event will be sent. The bookmark will report the ResourceVersion (RV) corresponding to the set of objects, and be marked with `\"k8s.io/initial-events-end\": \"true\"` annotation. Afterwards, the watch stream will proceed as usual, sending watch events corresponding to changes (subsequent to the RV) to objects watched.\n\nWhen `sendInitialEvents` option is set, we require `resourceVersionMatch` option to also be set. The semantic of the watch request is as following: - `resourceVersionMatch` = NotOlderThan\n is interpreted as \"data at least as new as the provided `resourceVersion`\"\n and the bookmark event is send when the state is synced\n to a `resourceVersion` at least as fresh as the one provided by the ListOptions.\n If `resourceVersion` is unset, this is interpreted as \"consistent read\" and the\n bookmark event is send when the state is synced at least to the moment\n when request started being processed.\n- `resourceVersionMatch` set to any other value or unset\n Invalid error is returned.\n\nDefaults to true if `resourceVersion=\"\"` or `resourceVersion=\"0\"` (for backward compatibility reasons) and to false otherwise.", + "schema": { + "type": "boolean", + "uniqueItems": true + } + }, + { + "name": "timeoutSeconds", + "in": "query", + "description": "Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity.", + "schema": { + "type": "integer", + "uniqueItems": true + } + }, + { + "name": "watch", + "in": "query", + "description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", + "schema": { + "type": "boolean", + "uniqueItems": true + } + } + ] + }, + "/apis/provisioning.grafana.app/v0alpha1/namespaces/{namespace}/jobs": { + "get": { + "tags": [ + "Job" + ], + "description": "list or watch objects of kind Job", + "operationId": "listJob", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.JobList" + } + }, + "application/json;stream=watch": { + "schema": { + "$ref": "#/components/schemas/com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.JobList" + } + }, + "application/vnd.kubernetes.protobuf": { + "schema": { + "$ref": "#/components/schemas/com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.JobList" + } + }, + "application/vnd.kubernetes.protobuf;stream=watch": { + "schema": { + "$ref": "#/components/schemas/com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.JobList" + } + }, + "application/yaml": { + "schema": { + "$ref": "#/components/schemas/com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.JobList" + } + } + } + } + }, + "x-kubernetes-action": "list", + "x-kubernetes-group-version-kind": { + "group": "provisioning.grafana.app", + "version": "v0alpha1", + "kind": "Job" + } + }, + "parameters": [ + { + "name": "allowWatchBookmarks", + "in": "query", + "description": "allowWatchBookmarks requests watch events with type \"BOOKMARK\". Servers that do not implement bookmarks may ignore this flag and bookmarks are sent at the server's discretion. Clients should not assume bookmarks are returned at any specific interval, nor may they assume the server will send any BOOKMARK event during a session. If this is not a watch, this field is ignored.", + "schema": { + "type": "boolean", + "uniqueItems": true + } + }, + { + "name": "continue", + "in": "query", + "description": "The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the \"next key\".\n\nThis field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications.", + "schema": { + "type": "string", + "uniqueItems": true + } + }, + { + "name": "fieldSelector", + "in": "query", + "description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.", + "schema": { + "type": "string", + "uniqueItems": true + } + }, + { + "name": "labelSelector", + "in": "query", + "description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + "schema": { + "type": "string", + "uniqueItems": true + } + }, + { + "name": "limit", + "in": "query", + "description": "limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true.\n\nThe server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned.", + "schema": { + "type": "integer", + "uniqueItems": true + } + }, + { + "name": "namespace", + "in": "path", + "description": "object name and auth scope, such as for teams and projects", + "required": true, + "schema": { + "type": "string", + "uniqueItems": true + } + }, + { + "name": "pretty", + "in": "query", + "description": "If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget).", + "schema": { + "type": "string", + "uniqueItems": true + } + }, + { + "name": "resourceVersion", + "in": "query", + "description": "resourceVersion sets a constraint on what resource versions a request may be served from. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details.\n\nDefaults to unset", + "schema": { + "type": "string", + "uniqueItems": true + } + }, + { + "name": "resourceVersionMatch", + "in": "query", + "description": "resourceVersionMatch determines how resourceVersion is applied to list calls. It is highly recommended that resourceVersionMatch be set for list calls where resourceVersion is set See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details.\n\nDefaults to unset", + "schema": { + "type": "string", + "uniqueItems": true + } + }, + { + "name": "sendInitialEvents", + "in": "query", + "description": "`sendInitialEvents=true` may be set together with `watch=true`. In that case, the watch stream will begin with synthetic events to produce the current state of objects in the collection. Once all such events have been sent, a synthetic \"Bookmark\" event will be sent. The bookmark will report the ResourceVersion (RV) corresponding to the set of objects, and be marked with `\"k8s.io/initial-events-end\": \"true\"` annotation. Afterwards, the watch stream will proceed as usual, sending watch events corresponding to changes (subsequent to the RV) to objects watched.\n\nWhen `sendInitialEvents` option is set, we require `resourceVersionMatch` option to also be set. The semantic of the watch request is as following: - `resourceVersionMatch` = NotOlderThan\n is interpreted as \"data at least as new as the provided `resourceVersion`\"\n and the bookmark event is send when the state is synced\n to a `resourceVersion` at least as fresh as the one provided by the ListOptions.\n If `resourceVersion` is unset, this is interpreted as \"consistent read\" and the\n bookmark event is send when the state is synced at least to the moment\n when request started being processed.\n- `resourceVersionMatch` set to any other value or unset\n Invalid error is returned.\n\nDefaults to true if `resourceVersion=\"\"` or `resourceVersion=\"0\"` (for backward compatibility reasons) and to false otherwise.", + "schema": { + "type": "boolean", + "uniqueItems": true + } + }, + { + "name": "timeoutSeconds", + "in": "query", + "description": "Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity.", + "schema": { + "type": "integer", + "uniqueItems": true + } + }, + { + "name": "watch", + "in": "query", + "description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", + "schema": { + "type": "boolean", + "uniqueItems": true + } + } + ] + }, + "/apis/provisioning.grafana.app/v0alpha1/namespaces/{namespace}/jobs/{name}": { + "get": { + "tags": [ + "Job" + ], + "description": "read the specified Job", + "operationId": "getJob", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.Job" + } + }, + "application/vnd.kubernetes.protobuf": { + "schema": { + "$ref": "#/components/schemas/com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.Job" + } + }, + "application/yaml": { + "schema": { + "$ref": "#/components/schemas/com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.Job" + } + } + } + } + }, + "x-kubernetes-action": "get", + "x-kubernetes-group-version-kind": { + "group": "provisioning.grafana.app", + "version": "v0alpha1", + "kind": "Job" + } + }, + "parameters": [ + { + "name": "name", + "in": "path", + "description": "name of the Job", + "required": true, + "schema": { + "type": "string", + "uniqueItems": true + } + }, + { + "name": "namespace", + "in": "path", + "description": "object name and auth scope, such as for teams and projects", + "required": true, + "schema": { + "type": "string", + "uniqueItems": true + } + }, + { + "name": "pretty", + "in": "query", + "description": "If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget).", + "schema": { + "type": "string", + "uniqueItems": true + } + } + ] + }, "/apis/provisioning.grafana.app/v0alpha1/namespaces/{namespace}/repositories": { "get": { "tags": [ @@ -1295,17 +1669,46 @@ }, "components": { "schemas": { - "com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.GitHubRepositoryConfig": { + "com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.ExportJobOptions": { "type": "object", + "required": [ + "identifier" + ], "properties": { "branch": { - "description": "The branch to use in the repository. By default, this is the main branch.", + "description": "Target branch for export (only git)", "type": "string" }, - "branchWorkflow": { - "description": "Whether we should commit to change branches and use a Pull Request flow to achieve this. By default, this is false (i.e. we will commit straight to the main branch).", + "folder": { + "description": "The source folder (or empty) to export", + "type": "string" + }, + "history": { + "description": "Preserve history (if possible)", "type": "boolean" }, + "identifier": { + "description": "Include the identifier in the exported metadata", + "type": "boolean", + "default": false + }, + "prefix": { + "description": "Target file prefix", + "type": "string" + } + } + }, + "com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.GitHubRepositoryConfig": { + "type": "object", + "required": [ + "branch" + ], + "properties": { + "branch": { + "description": "The branch to use in the repository.", + "type": "string", + "default": "" + }, "encryptedToken": { "description": "Token for accessing the repository, but encrypted. This is not possible to read back to a user decrypted.", "type": "string", @@ -1323,18 +1726,6 @@ "url": { "description": "The repository URL (e.g. `https://github.com/example/test`).", "type": "string" - }, - "workflows": { - "description": "Workflow allowed for changes to the repository. The order is relevant for defining the precedence of the workflows. Possible values: pull-request, branch, push.", - "type": "array", - "items": { - "type": "string", - "default": "", - "enum": [ - "branch", - "push" - ] - } } } }, @@ -1365,6 +1756,243 @@ } } }, + "com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.Job": { + "description": "The repository name and type are stored as labels", + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + "type": "string" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + "type": "string" + }, + "metadata": { + "default": {}, + "allOf": [ + { + "$ref": "#/components/schemas/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta" + } + ] + }, + "spec": { + "default": {}, + "allOf": [ + { + "$ref": "#/components/schemas/com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.JobSpec" + } + ] + }, + "status": { + "default": {}, + "allOf": [ + { + "$ref": "#/components/schemas/com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.JobStatus" + } + ] + } + }, + "x-kubernetes-group-version-kind": [ + { + "group": "provisioning.grafana.app", + "kind": "Job", + "version": "__internal" + }, + { + "group": "provisioning.grafana.app", + "kind": "Job", + "version": "v0alpha1" + } + ] + }, + "com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.JobList": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + "type": "string" + }, + "items": { + "type": "array", + "items": { + "default": {}, + "allOf": [ + { + "$ref": "#/components/schemas/com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.Job" + } + ] + } + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + "type": "string" + }, + "metadata": { + "default": {}, + "allOf": [ + { + "$ref": "#/components/schemas/io.k8s.apimachinery.pkg.apis.meta.v1.ListMeta" + } + ] + } + }, + "x-kubernetes-group-version-kind": [ + { + "group": "provisioning.grafana.app", + "kind": "JobList", + "version": "__internal" + }, + { + "group": "provisioning.grafana.app", + "kind": "JobList", + "version": "v0alpha1" + } + ] + }, + "com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.JobResourceSummary": { + "type": "object", + "properties": { + "create": { + "type": "integer", + "format": "int64" + }, + "delete": { + "type": "integer", + "format": "int64" + }, + "error": { + "description": "Create or update (export)", + "type": "integer", + "format": "int64" + }, + "errors": { + "description": "Report errors for this resource type This may not be an exhaustive list and recommend looking at the logs for more info", + "type": "array", + "items": { + "type": "string", + "default": "" + } + }, + "group": { + "type": "string" + }, + "noop": { + "description": "No action required (useful for sync)", + "type": "integer", + "format": "int64" + }, + "resource": { + "type": "string" + }, + "total": { + "type": "integer", + "format": "int64" + }, + "update": { + "type": "integer", + "format": "int64" + }, + "write": { + "type": "integer", + "format": "int64" + } + } + }, + "com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.JobSpec": { + "type": "object", + "required": [ + "action", + "repository" + ], + "properties": { + "action": { + "description": "Possible enum values:\n - `\"export\"` Export from grafana into the remote repository\n - `\"pr\"` Update a pull request -- send preview images, links etc\n - `\"sync\"` Sync the remote branch with the grafana instance", + "type": "string", + "default": "", + "enum": [ + "export", + "pr", + "sync" + ] + }, + "export": { + "description": "Required when the action is `export`", + "allOf": [ + { + "$ref": "#/components/schemas/com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.ExportJobOptions" + } + ] + }, + "pr": { + "description": "Pull request options", + "allOf": [ + { + "$ref": "#/components/schemas/com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.PullRequestJobOptions" + } + ] + }, + "repository": { + "description": "The the repository reference (for now also in labels)", + "type": "string", + "default": "" + }, + "sync": { + "description": "Required when the action is `sync`", + "allOf": [ + { + "$ref": "#/components/schemas/com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.SyncJobOptions" + } + ] + } + } + }, + "com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.JobStatus": { + "description": "The job status", + "type": "object", + "properties": { + "errors": { + "type": "array", + "items": { + "type": "string", + "default": "" + } + }, + "finished": { + "type": "integer", + "format": "int64" + }, + "message": { + "type": "string" + }, + "progress": { + "description": "Optional value 0-100 that can be set while running", + "type": "number", + "format": "double" + }, + "started": { + "type": "integer", + "format": "int64" + }, + "state": { + "description": "Possible enum values:\n - `\"error\"` Finished with errors\n - `\"pending\"` Job has been submitted, but not processed yet\n - `\"success\"` Finished with success\n - `\"working\"` The job is running", + "type": "string", + "enum": [ + "error", + "pending", + "success", + "working" + ] + }, + "summary": { + "description": "Summary of processed actions", + "type": "array", + "items": { + "$ref": "#/components/schemas/com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.JobResourceSummary" + } + } + } + }, "com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.LocalRepositoryConfig": { "type": "object", "properties": { @@ -1373,6 +2001,27 @@ } } }, + "com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.PullRequestJobOptions": { + "type": "object", + "properties": { + "hash": { + "type": "string" + }, + "pr": { + "description": "Pull request number (when appropriate)", + "type": "integer", + "format": "int32" + }, + "ref": { + "description": "The branch of commit hash", + "type": "string" + }, + "url": { + "description": "URL to the originator (eg, PR URL)", + "type": "string" + } + } + }, "com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.Repository": { "description": "When this code is changed, make sure to update the code generation. As of writing, this can be done via the hack dir in the root of the repo: ./hack/update-codegen.sh provisioning If you've opened the generated files in this dir at some point in VSCode, you may also have to re-open them to clear errors.", "type": "object", @@ -1472,7 +2121,7 @@ "type": "object", "required": [ "title", - "readOnly", + "workflows", "sync", "type" ], @@ -1497,11 +2146,6 @@ } ] }, - "readOnly": { - "description": "ReadOnly repository does not allow any write commands", - "type": "boolean", - "default": false - }, "sync": { "description": "Sync settings -- how values are pulled from the repository into grafana", "default": {}, @@ -1524,6 +2168,18 @@ "github", "local" ] + }, + "workflows": { + "description": "UI driven Workflow that allow changes to the contends of the repository. The order is relevant for defining the precedence of the workflows. When empty, the repository does not support any edits (eg, readonly)", + "type": "array", + "items": { + "type": "string", + "default": "", + "enum": [ + "branch", + "write" + ] + } } } }, @@ -1610,6 +2266,19 @@ } } }, + "com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.SyncJobOptions": { + "type": "object", + "required": [ + "incremental" + ], + "properties": { + "incremental": { + "description": "Incremental synchronization for versioned repositories", + "type": "boolean", + "default": false + } + } + }, "com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.SyncOptions": { "type": "object", "required": [ @@ -1650,10 +2319,6 @@ "type": "integer", "format": "int64" }, - "hash": { - "description": "The repository hash when the last sync ran", - "type": "string" - }, "incremental": { "description": "Incremental synchronization for versioned repositories", "type": "boolean" @@ -1662,6 +2327,10 @@ "description": "The ID for the job that ran this sync", "type": "string" }, + "lastRef": { + "description": "The repository ref when the last successful sync ran", + "type": "string" + }, "message": { "description": "Summary messages (will be shown to users)", "type": "array", diff --git a/pkg/tests/apis/provisioning/testdata/github-example.json b/pkg/tests/apis/provisioning/testdata/github-example.json index b737a51ff16..b9bcba83779 100644 --- a/pkg/tests/apis/provisioning/testdata/github-example.json +++ b/pkg/tests/apis/provisioning/testdata/github-example.json @@ -11,7 +11,6 @@ "github": { "url": "https://github.com/grafana/git-ui-sync-demo", "branch": "dummy-branch", - "branchWorkflow": true, "generateDashboardPreviews": true, "token": "github_pat_dummy" }, @@ -20,6 +19,6 @@ "target": "", "intervalSeconds": 60 }, - "readOnly": false + "workflows": ["push"] } } \ No newline at end of file diff --git a/pkg/tests/apis/provisioning/testdata/local-devenv.json b/pkg/tests/apis/provisioning/testdata/local-devenv.json index 39b8046a6ff..218f2715311 100644 --- a/pkg/tests/apis/provisioning/testdata/local-devenv.json +++ b/pkg/tests/apis/provisioning/testdata/local-devenv.json @@ -7,7 +7,7 @@ "spec": { "title": "Load devenv dashboards", "description": "Load /devenv/dev-dashboards (from root of repository)", - "readOnly": false, + "workflows": ["write"], "sync": { "enabled": true, "target": "mirror", diff --git a/public/api-merged.json b/public/api-merged.json index 04ffb5ef505..09bd1962ae9 100644 --- a/public/api-merged.json +++ b/public/api-merged.json @@ -1833,10 +1833,16 @@ { "type": "integer", "format": "int64", - "description": "Find annotations for a specified alert.", + "description": "Find annotations for a specified alert rule by its ID.\ndeprecated: AlertID is deprecated and will be removed in future versions. Please use AlertUID instead.", "name": "alertId", "in": "query" }, + { + "type": "string", + "description": "Find annotations for a specified alert rule by its UID.", + "name": "alertUID", + "in": "query" + }, { "type": "integer", "format": "int64", diff --git a/public/app/app.ts b/public/app/app.ts index 697e909fc37..7a3ba0bf140 100644 --- a/public/app/app.ts +++ b/public/app/app.ts @@ -205,7 +205,10 @@ export class GrafanaApp { setDataSourceSrv(dataSourceSrv); initWindowRuntime(); - if (contextSrv.user.orgRole !== '') { + // Do not pre-load apps if rendererDisableAppPluginsPreload is true and the request comes from the image renderer + const skipAppPluginsPreload = + config.featureToggles.rendererDisableAppPluginsPreload && contextSrv.user.authenticatedBy === 'render'; + if (contextSrv.user.orgRole !== '' && !skipAppPluginsPreload) { const appPluginsToAwait = getAppPluginsToAwait(); const appPluginsToPreload = getAppPluginsToPreload(); diff --git a/public/app/core/components/SharedPreferences/SharedPreferences.tsx b/public/app/core/components/SharedPreferences/SharedPreferences.tsx index fff3bd62ecb..dcc1a250133 100644 --- a/public/app/core/components/SharedPreferences/SharedPreferences.tsx +++ b/public/app/core/components/SharedPreferences/SharedPreferences.tsx @@ -18,13 +18,14 @@ import { Combobox, ComboboxOption, TextLink, + WeekStart, + isWeekStart, } from '@grafana/ui'; import { DashboardPicker } from 'app/core/components/Select/DashboardPicker'; import { t, Trans } from 'app/core/internationalization'; import { LANGUAGES, PSEUDO_LOCALE } from 'app/core/internationalization/constants'; import { PreferencesService } from 'app/core/services/PreferencesService'; import { changeTheme } from 'app/core/services/theme'; - export interface Props { resourceUri: string; disabled?: boolean; @@ -152,8 +153,8 @@ export class SharedPreferences extends PureComponent { this.setState({ timezone: timezone }); }; - onWeekStartChanged = (weekStart: string) => { - this.setState({ weekStart: weekStart }); + onWeekStartChanged = (weekStart?: WeekStart) => { + this.setState({ weekStart: weekStart ?? '' }); }; onHomeDashboardChanged = (dashboardUID: string) => { @@ -249,7 +250,7 @@ export class SharedPreferences extends PureComponent { data-testid={selectors.components.WeekStartPicker.containerV2} > diff --git a/public/app/features/alerting/state/ThresholdMapper.ts b/public/app/features/alerting/state/ThresholdMapper.ts index 265934a61fd..48b9b7c656a 100644 --- a/public/app/features/alerting/state/ThresholdMapper.ts +++ b/public/app/features/alerting/state/ThresholdMapper.ts @@ -29,6 +29,26 @@ export class ThresholdMapper { thresholds.push({ value: value, op: 'lt', visible }); break; } + case 'eq': { + const value = evaluator.params[0]; + thresholds.push({ value: value, op: 'eq', visible }); + break; + } + case 'ne': { + const value = evaluator.params[0]; + thresholds.push({ value: value, op: 'ne', visible }); + break; + } + case 'gte': { + const value = evaluator.params[0]; + thresholds.push({ value: value, op: 'ge', visible }); + break; + } + case 'lte': { + const value = evaluator.params[0]; + thresholds.push({ value: value, op: 'le', visible }); + break; + } case 'outside_range': { const value1 = evaluator.params[0]; const value2 = evaluator.params[1]; @@ -56,6 +76,33 @@ export class ThresholdMapper { } break; } + case 'outside_range_included': { + const value1 = evaluator.params[0]; + const value2 = evaluator.params[1]; + + if (value1 >= value2) { + thresholds.push({ value: value1, op: 'ge', visible }); + thresholds.push({ value: value2, op: 'le', visible }); + } else { + thresholds.push({ value: value1, op: 'le', visible }); + thresholds.push({ value: value2, op: 'ge', visible }); + } + + break; + } + case 'within_range_included': { + const value1 = evaluator.params[0]; + const value2 = evaluator.params[1]; + + if (value1 >= value2) { + thresholds.push({ value: value1, op: 'le', visible }); + thresholds.push({ value: value2, op: 'ge', visible }); + } else { + thresholds.push({ value: value1, op: 'ge', visible }); + thresholds.push({ value: value2, op: 'le', visible }); + } + break; + } } break; } diff --git a/public/app/features/alerting/state/alertDef.ts b/public/app/features/alerting/state/alertDef.ts index 96884ce8ae1..cdcdcbda7c1 100644 --- a/public/app/features/alerting/state/alertDef.ts +++ b/public/app/features/alerting/state/alertDef.ts @@ -32,16 +32,28 @@ const alertStateSortScore = { export enum EvalFunction { 'IsAbove' = 'gt', 'IsBelow' = 'lt', + 'IsEqual' = 'eq', + 'IsNotEqual' = 'ne', + 'IsGreaterThanEqual' = 'gte', + 'IsLessThanEqual' = 'lte', 'IsOutsideRange' = 'outside_range', 'IsWithinRange' = 'within_range', + 'IsWithinRangeIncluded' = 'within_range_included', + 'IsOutsideRangeIncluded' = 'outside_range_included', 'HasNoValue' = 'no_value', } const evalFunctions = [ { value: EvalFunction.IsAbove, text: 'IS ABOVE' }, { value: EvalFunction.IsBelow, text: 'IS BELOW' }, + { value: EvalFunction.IsEqual, text: 'IS EQUAL TO' }, + { value: EvalFunction.IsNotEqual, text: 'IS NOT EQUAL TO' }, + { value: EvalFunction.IsGreaterThanEqual, text: 'IS ABOVE OR EQUAL TO' }, + { value: EvalFunction.IsLessThanEqual, text: 'IS BELOW OR EQUAL TO' }, { value: EvalFunction.IsOutsideRange, text: 'IS OUTSIDE RANGE' }, { value: EvalFunction.IsWithinRange, text: 'IS WITHIN RANGE' }, + { value: EvalFunction.IsOutsideRangeIncluded, text: 'IS OUTSIDE RANGE INCLUDED' }, + { value: EvalFunction.IsWithinRangeIncluded, text: 'IS WITHIN RANGE INCLUDED' }, { value: EvalFunction.HasNoValue, text: 'HAS NO VALUE' }, ]; diff --git a/public/app/features/alerting/unified/GrafanaRuleQueryViewer.tsx b/public/app/features/alerting/unified/GrafanaRuleQueryViewer.tsx index 1839ea4c8eb..10126744321 100644 --- a/public/app/features/alerting/unified/GrafanaRuleQueryViewer.tsx +++ b/public/app/features/alerting/unified/GrafanaRuleQueryViewer.tsx @@ -538,5 +538,10 @@ const getCommonQueryStyles = (theme: GrafanaTheme2) => ({ }); function isRangeEvaluator(evaluator: { params: number[]; type: EvalFunction }) { - return evaluator.type === EvalFunction.IsWithinRange || evaluator.type === EvalFunction.IsOutsideRange; + return ( + evaluator.type === EvalFunction.IsWithinRange || + evaluator.type === EvalFunction.IsOutsideRange || + evaluator.type === EvalFunction.IsOutsideRangeIncluded || + evaluator.type === EvalFunction.IsWithinRangeIncluded + ); } diff --git a/public/app/features/alerting/unified/api/annotations.test.ts b/public/app/features/alerting/unified/api/annotations.test.ts index 01da8c9da97..f80d7e8f22c 100644 --- a/public/app/features/alerting/unified/api/annotations.test.ts +++ b/public/app/features/alerting/unified/api/annotations.test.ts @@ -21,7 +21,7 @@ describe('annotations', () => { it('should fetch annotation for an alertId', () => { const ALERT_ID = 'abc123'; fetchAnnotations(ALERT_ID); - expect(get).toBeCalledWith('/api/annotations', { alertId: ALERT_ID }); + expect(get).toBeCalledWith('/api/annotations', { alertUID: ALERT_ID }); }); }); diff --git a/public/app/features/alerting/unified/api/annotations.ts b/public/app/features/alerting/unified/api/annotations.ts index 39195dc1f48..2e0d577ffbf 100644 --- a/public/app/features/alerting/unified/api/annotations.ts +++ b/public/app/features/alerting/unified/api/annotations.ts @@ -1,10 +1,10 @@ import { getBackendSrv } from '@grafana/runtime'; import { StateHistoryItem } from 'app/types/unified-alerting'; -export function fetchAnnotations(alertId: string): Promise { +export function fetchAnnotations(alertUID: string): Promise { return getBackendSrv() .get('/api/annotations', { - alertId, + alertUID, }) .then((result) => { return result?.sort(sortStateHistory); diff --git a/public/app/features/alerting/unified/components/rule-editor/util.ts b/public/app/features/alerting/unified/components/rule-editor/util.ts index 3933de4f48e..b8e20cba6b4 100644 --- a/public/app/features/alerting/unified/components/rule-editor/util.ts +++ b/public/app/features/alerting/unified/components/rule-editor/util.ts @@ -279,6 +279,53 @@ export function getThresholdsForQueries(queries: AlertQuery[], condition: string ); } + if (type === EvalFunction.IsWithinRangeIncluded) { + thresholds[refId].config.steps.push( + ...[ + { + value: -Infinity, + color: 'transparent', + }, + { + value: values[0], + color: config.theme2.colors.error.main, + }, + { + value: values[1], + color: config.theme2.colors.error.main, + }, + { + value: values[1], + color: 'transparent', + }, + ] + ); + } + + if (type === EvalFunction.IsOutsideRangeIncluded) { + thresholds[refId].config.steps.push( + ...[ + { + value: -Infinity, + color: config.theme2.colors.error.main, + }, + // we have to duplicate this value, or the graph will not display the handle in the right color + { + value: values[0], + color: config.theme2.colors.error.main, + }, + { + value: values[0], + color: 'transparent', + }, + { + value: values[1], + color: config.theme2.colors.error.main, + }, + ] + ); + } + // now also sort the threshold values, if we don't then they will look weird in the time series panel // TODO this doesn't work for negative values for now, those need to be sorted inverse thresholds[refId].config.steps.sort((a, b) => a.value - b.value); @@ -292,7 +339,10 @@ export function getThresholdsForQueries(queries: AlertQuery[], condition: string function isRangeCondition(condition: ClassicCondition) { return ( - condition.evaluator.type === EvalFunction.IsWithinRange || condition.evaluator.type === EvalFunction.IsOutsideRange + condition.evaluator.type === EvalFunction.IsWithinRange || + condition.evaluator.type === EvalFunction.IsOutsideRange || + condition.evaluator.type === EvalFunction.IsOutsideRangeIncluded || + condition.evaluator.type === EvalFunction.IsWithinRangeIncluded ); } diff --git a/public/app/features/alerting/unified/components/rule-viewer/tabs/History.tsx b/public/app/features/alerting/unified/components/rule-viewer/tabs/History.tsx index bed499ce2a2..b946c0a65f7 100644 --- a/public/app/features/alerting/unified/components/rule-viewer/tabs/History.tsx +++ b/public/app/features/alerting/unified/components/rule-viewer/tabs/History.tsx @@ -26,13 +26,12 @@ const History = ({ rule }: HistoryProps) => { ? StateHistoryImplementation.Loki : StateHistoryImplementation.Annotations; - const ruleID = rule.grafana_alert.id ?? ''; const ruleUID = rule.grafana_alert.uid; return ( {implementation === StateHistoryImplementation.Loki && } - {implementation === StateHistoryImplementation.Annotations && } + {implementation === StateHistoryImplementation.Annotations && } ); }; diff --git a/public/app/features/alerting/unified/components/rules/state-history/StateHistory.tsx b/public/app/features/alerting/unified/components/rules/state-history/StateHistory.tsx index a0388b41464..128dbaf1087 100644 --- a/public/app/features/alerting/unified/components/rules/state-history/StateHistory.tsx +++ b/public/app/features/alerting/unified/components/rules/state-history/StateHistory.tsx @@ -27,16 +27,16 @@ type StateHistoryMap = Record; type StateHistoryRow = DynamicTableItemProps; interface Props { - alertId: string; + ruleUID: string; } -const StateHistory = ({ alertId }: Props) => { +const StateHistory = ({ ruleUID }: Props) => { const [textFilter, setTextFilter] = useState(''); const handleTextFilter = useCallback((event: FormEvent) => { setTextFilter(event.currentTarget.value); }, []); - const { loading, error, result = [] } = useManagedAlertStateHistory(alertId); + const { loading, error, result = [] } = useManagedAlertStateHistory(ruleUID); const styles = useStyles2(getStyles); diff --git a/public/app/features/alerting/unified/hooks/useFolder.ts b/public/app/features/alerting/unified/hooks/useFolder.ts index 8939ae8ad4c..7b06bf92020 100644 --- a/public/app/features/alerting/unified/hooks/useFolder.ts +++ b/public/app/features/alerting/unified/hooks/useFolder.ts @@ -1,35 +1,23 @@ -import { useEffect } from 'react'; +import { skipToken } from '@reduxjs/toolkit/query/react'; -import { FolderDTO, useDispatch } from 'app/types'; - -import { fetchFolderIfNotFetchedAction } from '../state/actions'; -import { initialAsyncRequestState } from '../utils/redux'; - -import { useUnifiedAlertingSelector } from './useUnifiedAlertingSelector'; +import { useGetFolderQuery } from 'app/features/browse-dashboards/api/browseDashboardsAPI'; +import { FolderDTO } from 'app/types'; interface ReturnBag { folder?: FolderDTO; loading: boolean; } +/** + * Returns a folderDTO for the given uid – uses cached values + * @TODO propagate error state + */ export function useFolder(uid?: string): ReturnBag { - const dispatch = useDispatch(); - const folderRequests = useUnifiedAlertingSelector((state) => state.folders); - useEffect(() => { - if (uid) { - dispatch(fetchFolderIfNotFetchedAction(uid)); - } - }, [dispatch, uid]); + const fetchFolderState = useGetFolderQuery(uid || skipToken); - if (uid) { - const request = folderRequests[uid] || initialAsyncRequestState; - return { - folder: request.result, - loading: request.loading, - }; - } return { - loading: false, + loading: fetchFolderState.isLoading, + folder: fetchFolderState.data, }; } @@ -39,6 +27,6 @@ export function stringifyFolder({ title, parents }: FolderDTO) { : encodeTitle(title); } -export function encodeTitle(title: string): string { +function encodeTitle(title: string): string { return title.replaceAll('/', '\\/'); } diff --git a/public/app/features/alerting/unified/hooks/useManagedAlertStateHistory.ts b/public/app/features/alerting/unified/hooks/useManagedAlertStateHistory.ts index 43b10d666f5..e7902fcf507 100644 --- a/public/app/features/alerting/unified/hooks/useManagedAlertStateHistory.ts +++ b/public/app/features/alerting/unified/hooks/useManagedAlertStateHistory.ts @@ -8,15 +8,15 @@ import { AsyncRequestState } from '../utils/redux'; import { useUnifiedAlertingSelector } from './useUnifiedAlertingSelector'; -export function useManagedAlertStateHistory(alertId: string) { +export function useManagedAlertStateHistory(ruleUID: string) { const dispatch = useDispatch(); const history = useUnifiedAlertingSelector>( (state) => state.managedAlertStateHistory ); useEffect(() => { - dispatch(fetchGrafanaAnnotationsAction(alertId)); - }, [dispatch, alertId]); + dispatch(fetchGrafanaAnnotationsAction(ruleUID)); + }, [dispatch, ruleUID]); return history; } diff --git a/public/app/features/alerting/unified/hooks/useStateHistoryModal.tsx b/public/app/features/alerting/unified/hooks/useStateHistoryModal.tsx index c5c527c414a..8c33574bf6c 100644 --- a/public/app/features/alerting/unified/hooks/useStateHistoryModal.tsx +++ b/public/app/features/alerting/unified/hooks/useStateHistoryModal.tsx @@ -61,7 +61,7 @@ function useStateHistoryModal() { {implementation === StateHistoryImplementation.Loki && } {implementation === StateHistoryImplementation.Annotations && ( - + )} diff --git a/public/app/features/alerting/unified/state/actions.ts b/public/app/features/alerting/unified/state/actions.ts index 7c05181fd53..5b03e36fe6b 100644 --- a/public/app/features/alerting/unified/state/actions.ts +++ b/public/app/features/alerting/unified/state/actions.ts @@ -10,11 +10,10 @@ import { Receiver, TestReceiversAlert, } from 'app/plugins/datasource/alertmanager/types'; -import { FolderDTO, ThunkResult } from 'app/types'; +import { ThunkResult } from 'app/types'; import { RuleIdentifier, RuleNamespace, StateHistoryItem } from 'app/types/unified-alerting'; import { RulerRuleDTO, RulerRulesConfigDTO } from 'app/types/unified-alerting-dto'; -import { backendSrv } from '../../../../core/services/backend_srv'; import { withPromRulesMetadataLogging, withRulerRulesMetadataLogging } from '../Analytics'; import { deleteAlertManagerConfig, @@ -183,7 +182,7 @@ export function fetchAllPromRulesAction( export const fetchGrafanaAnnotationsAction = createAsyncThunk( 'unifiedalerting/fetchGrafanaAnnotations', - (alertId: string): Promise => withSerializedError(fetchAnnotations(alertId)) + (ruleUID: string): Promise => withSerializedError(fetchAnnotations(ruleUID)) ); interface UpdateAlertManagerConfigActionOptions { @@ -241,19 +240,6 @@ export const updateAlertManagerConfigAction = createAsyncThunk => withSerializedError(backendSrv.getFolderByUid(uid, { withAccessControl: true })) -); - -export const fetchFolderIfNotFetchedAction = (uid: string): ThunkResult => { - return (dispatch, getState) => { - if (!getState().unifiedAlerting.folders[uid]?.dispatched) { - dispatch(fetchFolderAction(uid)); - } - }; -}; - export const fetchAlertGroupsAction = createAsyncThunk( 'unifiedalerting/fetchAlertGroups', (alertManagerSourceName: string): Promise => { diff --git a/public/app/features/alerting/unified/state/reducers.ts b/public/app/features/alerting/unified/state/reducers.ts index 19153a3bee1..71ba6a54e66 100644 --- a/public/app/features/alerting/unified/state/reducers.ts +++ b/public/app/features/alerting/unified/state/reducers.ts @@ -5,7 +5,6 @@ import { createAsyncMapSlice, createAsyncSlice } from '../utils/redux'; import { deleteAlertManagerConfigAction, fetchAlertGroupsAction, - fetchFolderAction, fetchGrafanaAnnotationsAction, fetchPromRulesAction, fetchRulerRulesAction, @@ -19,7 +18,6 @@ export const reducer = combineReducers({ .reducer, saveAMConfig: createAsyncSlice('saveAMConfig', updateAlertManagerConfigAction).reducer, deleteAMConfig: createAsyncSlice('deleteAMConfig', deleteAlertManagerConfigAction).reducer, - folders: createAsyncMapSlice('folders', fetchFolderAction, (uid) => uid).reducer, amAlertGroups: createAsyncMapSlice( 'amAlertGroups', fetchAlertGroupsAction, diff --git a/public/app/features/alerting/unified/utils/cloud-alertmanager-notifier-types.ts b/public/app/features/alerting/unified/utils/cloud-alertmanager-notifier-types.ts index a172c9cd19d..96bc19b4aff 100644 --- a/public/app/features/alerting/unified/utils/cloud-alertmanager-notifier-types.ts +++ b/public/app/features/alerting/unified/utils/cloud-alertmanager-notifier-types.ts @@ -400,6 +400,14 @@ export const cloudNotifierTypes: Array> = [ }, } ), + option( + 'timeout', + 'Timeout', + 'The maximum time to wait for a webhook request to complete, before failing the request and allowing it to be retried. The default value of 0s indicates that no timeout should be applied. NOTE: This will have no effect if set higher than the group_interval.', + { + placeholder: 'Use duration format, for example: 1.2s, 100ms', + } + ), httpConfigOption, ], }, diff --git a/public/app/features/browse-dashboards/api/browseDashboardsAPI.ts b/public/app/features/browse-dashboards/api/browseDashboardsAPI.ts index fb411699d8a..51f08201927 100644 --- a/public/app/features/browse-dashboards/api/browseDashboardsAPI.ts +++ b/public/app/features/browse-dashboards/api/browseDashboardsAPI.ts @@ -446,6 +446,7 @@ export const { useDeleteItemsMutation, useGetAffectedItemsQuery, useGetFolderQuery, + useLazyGetFolderQuery, useMoveFolderMutation, useMoveItemsMutation, useNewFolderMutation, diff --git a/public/app/features/dashboard-scene/edit-pane/DashboardAddPane.tsx b/public/app/features/dashboard-scene/edit-pane/DashboardAddPane.tsx new file mode 100644 index 00000000000..f58103b09c9 --- /dev/null +++ b/public/app/features/dashboard-scene/edit-pane/DashboardAddPane.tsx @@ -0,0 +1,75 @@ +import { selectors } from '@grafana/e2e-selectors'; +import { Box, Card, Icon } from '@grafana/ui'; +import { t, Trans } from 'app/core/internationalization'; + +import { DashboardInteractions } from '../utils/interactions'; +import { getDashboardSceneFor } from '../utils/utils'; + +import { DashboardEditPane } from './DashboardEditPane'; + +export interface Props { + editPane: DashboardEditPane; +} + +export function DashboardAddPane({ editPane }: Props) { + const dashboard = getDashboardSceneFor(editPane); + + return ( + + dashboard.onCreateNewPanel()} + data-testid={selectors.components.PageToolbar.itemButton('add_visualization')} + title={t('dashboard.toolbar.add-panel-description', 'A container for visualizations and other content')} + > + + Panel + + + + + + { + dashboard.onShowAddLibraryPanelDrawer(); + DashboardInteractions.toolbarAddButtonClicked({ item: 'add_library_panel' }); + }} + data-testid={selectors.pages.AddDashboard.itemButton('Add new panel from panel library menu item')} + title={t( + 'dashboard.toolbar.libray-panel-description', + 'Libray panels allow you share and reuse panels between dashboards' + )} + > + + Import library panel + + + + + + dashboard.onCreateNewRow()} + data-testid={selectors.components.PageToolbar.itemButton('add_row')} + title={t('dashboard.toolbar.row-description', 'A group of panels with an optional header')} + > + + Row + + + + + + dashboard.onCreateNewTab()} + data-testid={selectors.components.PageToolbar.itemButton('add_tab')} + title={t('dashboard.toolbar.tabs-description', 'Break up your dashboard into different horizontal tabs')} + > + + Tab + + + + + + + ); +} diff --git a/public/app/features/dashboard-scene/edit-pane/DashboardEditPane.tsx b/public/app/features/dashboard-scene/edit-pane/DashboardEditPane.tsx index e2e2b091420..fbaf5aa5260 100644 --- a/public/app/features/dashboard-scene/edit-pane/DashboardEditPane.tsx +++ b/public/app/features/dashboard-scene/edit-pane/DashboardEditPane.tsx @@ -4,12 +4,20 @@ import { useEffect, useRef } from 'react'; import { GrafanaTheme2 } from '@grafana/data'; import { SceneObjectState, SceneObjectBase, SceneObject, sceneGraph, useSceneObjectState } from '@grafana/scenes'; -import { ElementSelectionContextItem, ElementSelectionContextState, ToolbarButton, useStyles2 } from '@grafana/ui'; +import { + ElementSelectionContextItem, + ElementSelectionContextState, + Tab, + TabsBar, + ToolbarButton, + useStyles2, +} from '@grafana/ui'; import { t } from 'app/core/internationalization'; import { isInCloneChain } from '../utils/clone'; import { getDashboardSceneFor } from '../utils/utils'; +import { DashboardAddPane } from './DashboardAddPane'; import { ElementEditPane } from './ElementEditPane'; import { ElementSelection } from './ElementSelection'; import { useEditableElement } from './useEditableElement'; @@ -17,8 +25,11 @@ import { useEditableElement } from './useEditableElement'; export interface DashboardEditPaneState extends SceneObjectState { selection?: ElementSelection; selectionContext: ElementSelectionContextState; + tab?: EditPaneTab; } +export type EditPaneTab = 'add' | 'configure' | 'outline'; + export class DashboardEditPane extends SceneObjectBase { public constructor() { super({ @@ -122,6 +133,10 @@ export class DashboardEditPane extends SceneObjectBase { }, }); } + + public onChangeTab = (tab: EditPaneTab) => { + this.setState({ tab }); + }; } export interface Props { @@ -157,7 +172,7 @@ export function DashboardEditPaneRenderer({ editPane, isCollapsed, onToggleColla } }, [editPane, isCollapsed]); - const { selection } = useSceneObjectState(editPane, { shouldActivateOrKeepAlive: true }); + const { selection, tab = 'configure' } = useSceneObjectState(editPane, { shouldActivateOrKeepAlive: true }); const styles = useStyles2(getStyles); const paneRef = useRef(null); const editableElement = useEditableElement(selection); @@ -191,7 +206,28 @@ export function DashboardEditPaneRenderer({ editPane, isCollapsed, onToggleColla return (
    - + + editPane.onChangeTab('add')} + /> + editPane.onChangeTab('configure')} + /> + editPane.onChangeTab('outline')} + /> + +
    + {tab === 'add' && } + {tab === 'configure' && } + {tab === 'outline' &&
    } +
    ); } @@ -202,11 +238,21 @@ function getStyles(theme: GrafanaTheme2) { display: 'flex', flexDirection: 'column', flex: '1 1 0', + }), + tabContent: css({ + display: 'flex', + flex: '1 1 0', + flexDirection: 'column', + minHeight: 0, overflow: 'auto', }), rotate180: css({ rotate: '180deg', }), + tabsbar: css({ + padding: theme.spacing(0, 1), + margin: theme.spacing(0.5, 1), + }), expandOptionsWrapper: css({ display: 'flex', flexDirection: 'column', diff --git a/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx b/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx index edda9d01268..d5564aa2814 100644 --- a/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx +++ b/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx @@ -156,83 +156,6 @@ export function ToolbarActions({ dashboard }: Props) { } if (dashboardNewLayouts) { - leftActions.push({ - group: 'add-panel', - condition: isEditingAndShowingDashboard, - render: () => ( - - ), - }); - leftActions.push({ - group: 'add-panel', - condition: isEditingAndShowingDashboard, - render: () => ( - - ), - }); - leftActions.push({ - group: 'add-panel', - condition: isEditingAndShowingDashboard, - render: () => ( - - ), - }); - leftActions.push({ - group: 'add-panel', - condition: isEditingAndShowingDashboard, - render: () => ( - - ), - }); leftActions.push({ group: 'hidden-elements', condition: isEditingAndShowingDashboard, diff --git a/public/app/features/dashboard-scene/scene/layout-tabs/TabItem.tsx b/public/app/features/dashboard-scene/scene/layout-tabs/TabItem.tsx index 73ce7af6b19..4f4a2b45766 100644 --- a/public/app/features/dashboard-scene/scene/layout-tabs/TabItem.tsx +++ b/public/app/features/dashboard-scene/scene/layout-tabs/TabItem.tsx @@ -70,10 +70,6 @@ export class TabItem return new TabItems(items.filter((item) => item instanceof TabItem)); } - public onChangeTab() { - this.getParentLayout().changeTab(this); - } - public onChangeTitle(title: string) { this.setState({ title }); } diff --git a/public/app/features/dashboard-scene/scene/layout-tabs/TabItemRenderer.tsx b/public/app/features/dashboard-scene/scene/layout-tabs/TabItemRenderer.tsx index 782fa9eeb3b..37c653ab354 100644 --- a/public/app/features/dashboard-scene/scene/layout-tabs/TabItemRenderer.tsx +++ b/public/app/features/dashboard-scene/scene/layout-tabs/TabItemRenderer.tsx @@ -1,5 +1,7 @@ import { useMemo } from 'react'; +import { useLocation } from 'react-router'; +import { locationUtil } from '@grafana/data'; import { SceneComponentProps, sceneGraph } from '@grafana/scenes'; import { Tab, useElementSelection } from '@grafana/ui'; @@ -12,29 +14,27 @@ export function TabItemRenderer({ model }: SceneComponentProps) { const { title, key } = model.useState(); const isClone = useMemo(() => isClonedKey(key!), [key]); const parentLayout = model.getParentLayout(); - const { currentTab } = parentLayout.useState(); + const { tabs, currentTabIndex } = parentLayout.useState(); const dashboard = getDashboardSceneFor(model); const { isEditing } = dashboard.useState(); const titleInterpolated = sceneGraph.interpolate(model, title, undefined, 'text'); const { isSelected, onSelect } = useElementSelection(key); + const myIndex = tabs.findIndex((tab) => tab === model); + const isActive = myIndex === currentTabIndex; + const location = useLocation(); + const href = locationUtil.getUrlForPartial(location, { tab: myIndex }); return ( { - evt.stopPropagation(); - - if (isEditing) { - if (isClone) { - dashboard.state.editPane.clearSelection(); - } else { - onSelect?.(evt); - } + if (isEditing && isActive && !isClone) { + evt.stopPropagation(); + onSelect?.(evt); } - - parentLayout.changeTab(model); }} /> ); diff --git a/public/app/features/dashboard-scene/scene/layout-tabs/TabsLayoutManager.tsx b/public/app/features/dashboard-scene/scene/layout-tabs/TabsLayoutManager.tsx index daa86286dae..3e2c338b26f 100644 --- a/public/app/features/dashboard-scene/scene/layout-tabs/TabsLayoutManager.tsx +++ b/public/app/features/dashboard-scene/scene/layout-tabs/TabsLayoutManager.tsx @@ -1,4 +1,10 @@ -import { SceneObjectBase, SceneObjectState, VizPanel } from '@grafana/scenes'; +import { + SceneObjectBase, + SceneObjectState, + SceneObjectUrlSyncConfig, + SceneObjectUrlValues, + VizPanel, +} from '@grafana/scenes'; import { t } from 'app/core/internationalization'; import { DashboardLayoutManager } from '../types/DashboardLayoutManager'; @@ -9,7 +15,7 @@ import { TabsLayoutManagerRenderer } from './TabsLayoutManagerRenderer'; interface TabsLayoutManagerState extends SceneObjectState { tabs: TabItem[]; - currentTab: TabItem; + currentTabIndex: number; } export class TabsLayoutManager extends SceneObjectBase implements DashboardLayoutManager { @@ -26,14 +32,42 @@ export class TabsLayoutManager extends SceneObjectBase i }, id: 'tabs-layout', createFromLayout: TabsLayoutManager.createFromLayout, - kind: 'TabsLayout', }; public readonly descriptor = TabsLayoutManager.descriptor; + protected _urlSync = new SceneObjectUrlSyncConfig(this, { keys: ['tab'] }); + + public constructor(state: Partial) { + super({ + ...state, + tabs: state.tabs ?? [new TabItem()], + currentTabIndex: state.currentTabIndex ?? 0, + }); + } + + public getUrlState() { + return { tab: this.state.currentTabIndex.toString() }; + } + + public updateFromUrl(values: SceneObjectUrlValues) { + if (!values.tab) { + return; + } + if (typeof values.tab === 'string') { + this.setState({ currentTabIndex: parseInt(values.tab, 10) }); + } + } + + public getCurrentTab(): TabItem { + return this.state.tabs.length > this.state.currentTabIndex + ? this.state.tabs[this.state.currentTabIndex] + : this.state.tabs[0]; + } + public addPanel(vizPanel: VizPanel) { - this.state.currentTab.getLayout().addPanel(vizPanel); + this.getCurrentTab().getLayout().addPanel(vizPanel); } public getVizPanels(): VizPanel[] { @@ -62,12 +96,12 @@ export class TabsLayoutManager extends SceneObjectBase i } public addNewRow() { - this.state.currentTab.getLayout().addNewRow(); + this.getCurrentTab().getLayout().addNewRow(); } public addNewTab() { const currentTab = new TabItem(); - this.setState({ tabs: [...this.state.tabs, currentTab], currentTab }); + this.setState({ tabs: [...this.state.tabs, currentTab], currentTabIndex: this.state.tabs.length }); } public editModeChanged(isEditing: boolean) { @@ -78,32 +112,33 @@ export class TabsLayoutManager extends SceneObjectBase i this.state.tabs.forEach((tab) => tab.getLayout().activateRepeaters?.()); } - public removeTab(tab: TabItem) { - if (this.state.currentTab === tab) { - const currentTabIndex = this.state.tabs.indexOf(tab); - const nextTabIndex = currentTabIndex === 0 ? 1 : currentTabIndex - 1; - const nextTab = this.state.tabs[nextTabIndex]; - this.setState({ tabs: this.state.tabs.filter((t) => t !== tab), currentTab: nextTab }); + public removeTab(tabToRemove: TabItem) { + // Do not allow removing last tab (for now) + if (this.state.tabs.length === 1) { return; } - const filteredTab = this.state.tabs.filter((tab) => tab !== this.state.currentTab); + const currentTab = this.getCurrentTab(); + + if (currentTab === tabToRemove) { + const nextTabIndex = this.state.currentTabIndex > 0 ? this.state.currentTabIndex - 1 : 0; + this.setState({ tabs: this.state.tabs.filter((t) => t !== tabToRemove), currentTabIndex: nextTabIndex }); + return; + } + + const filteredTab = this.state.tabs.filter((tab) => tab !== tabToRemove); const tabs = filteredTab.length === 0 ? [new TabItem()] : filteredTab; - this.setState({ tabs, currentTab: tabs[tabs.length - 1] }); - } - - public changeTab(tab: TabItem) { - this.setState({ currentTab: tab }); + this.setState({ tabs, currentTabIndex: 0 }); } public static createEmpty(): TabsLayoutManager { const tab = new TabItem(); - return new TabsLayoutManager({ tabs: [tab], currentTab: tab }); + return new TabsLayoutManager({ tabs: [tab] }); } public static createFromLayout(layout: DashboardLayoutManager): TabsLayoutManager { const tab = new TabItem({ layout: layout.clone() }); - return new TabsLayoutManager({ tabs: [tab], currentTab: tab }); + return new TabsLayoutManager({ tabs: [tab] }); } } diff --git a/public/app/features/dashboard-scene/scene/layout-tabs/TabsLayoutManagerRenderer.tsx b/public/app/features/dashboard-scene/scene/layout-tabs/TabsLayoutManagerRenderer.tsx index 68d4840ae19..443ae6e1f1c 100644 --- a/public/app/features/dashboard-scene/scene/layout-tabs/TabsLayoutManagerRenderer.tsx +++ b/public/app/features/dashboard-scene/scene/layout-tabs/TabsLayoutManagerRenderer.tsx @@ -8,7 +8,8 @@ import { TabsLayoutManager } from './TabsLayoutManager'; export function TabsLayoutManagerRenderer({ model }: SceneComponentProps) { const styles = useStyles2(getStyles); - const { tabs, currentTab } = model.useState(); + const { tabs, currentTabIndex } = model.useState(); + const currentTab = tabs[currentTabIndex]; const { layout } = currentTab.useState(); return ( @@ -18,7 +19,9 @@ export function TabsLayoutManagerRenderer({ model }: SceneComponentProps ))} - {layout && } + + {currentTab && } + ); } diff --git a/public/app/features/dashboard-scene/serialization/__snapshots__/transformSceneToSaveModel.test.ts.snap b/public/app/features/dashboard-scene/serialization/__snapshots__/transformSceneToSaveModel.test.ts.snap index 8146499446c..585b51daf4e 100644 --- a/public/app/features/dashboard-scene/serialization/__snapshots__/transformSceneToSaveModel.test.ts.snap +++ b/public/app/features/dashboard-scene/serialization/__snapshots__/transformSceneToSaveModel.test.ts.snap @@ -334,7 +334,6 @@ exports[`transformSceneToSaveModel Given a scene with rows Should transform back "title": "Repeating rows", "uid": "Repeating-rows-uid", "version": 1, - "weekStart": "", } `; diff --git a/public/app/features/dashboard-scene/serialization/layoutSerializers/TabsLayoutSerializer.ts b/public/app/features/dashboard-scene/serialization/layoutSerializers/TabsLayoutSerializer.ts index d6eb10803a1..d5093fb4663 100644 --- a/public/app/features/dashboard-scene/serialization/layoutSerializers/TabsLayoutSerializer.ts +++ b/public/app/features/dashboard-scene/serialization/layoutSerializers/TabsLayoutSerializer.ts @@ -44,6 +44,6 @@ export class TabsLayoutSerializer implements LayoutManagerSerializer { layout: layoutSerializerRegistry.get(layout.kind).serializer.deserialize(layout, elements, preload), }); }); - return new TabsLayoutManager({ tabs, currentTab: tabs[0] }); + return new TabsLayoutManager({ tabs }); } } diff --git a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts index b5ca18ea717..b271697a87e 100644 --- a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts +++ b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts @@ -22,6 +22,7 @@ import { SceneInteractionProfileEvent, SceneObjectState, } from '@grafana/scenes'; +import { isWeekStart } from '@grafana/ui'; import { contextSrv } from 'app/core/core'; import { DashboardModel } from 'app/features/dashboard/state/DashboardModel'; import { PanelModel } from 'app/features/dashboard/state/PanelModel'; @@ -274,7 +275,7 @@ export function createDashboardSceneFromDashboardModel(oldModel: DashboardModel, to: oldModel.time.to, fiscalYearStartMonth: oldModel.fiscalYearStartMonth, timeZone: oldModel.timezone, - weekStart: oldModel.weekStart, + weekStart: isWeekStart(oldModel.weekStart) ? oldModel.weekStart : undefined, UNSAFE_nowDelay: oldModel.timepicker?.nowDelay, }), $variables: variables, diff --git a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModelSchemaV2.test.ts b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModelSchemaV2.test.ts index 4ff7c331b78..050565bc711 100644 --- a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModelSchemaV2.test.ts +++ b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModelSchemaV2.test.ts @@ -549,14 +549,7 @@ describe('dynamic layouts', () => { }), ]; - const scene = setupDashboardScene( - getMinimalSceneState( - new TabsLayoutManager({ - currentTab: tabs[0], - tabs, - }) - ) - ); + const scene = setupDashboardScene(getMinimalSceneState(new TabsLayoutManager({ tabs }))); const result = transformSceneToSaveModelSchemaV2(scene); expect(result.layout.kind).toBe('TabsLayout'); const tabsLayout = result.layout.spec as TabsLayoutSpec; diff --git a/public/app/features/dashboard-scene/settings/GeneralSettingsEditView.tsx b/public/app/features/dashboard-scene/settings/GeneralSettingsEditView.tsx index ef7ae0489e6..d688616afc0 100644 --- a/public/app/features/dashboard-scene/settings/GeneralSettingsEditView.tsx +++ b/public/app/features/dashboard-scene/settings/GeneralSettingsEditView.tsx @@ -123,7 +123,7 @@ export class GeneralSettingsEditView }); }; - public onWeekStartChange = (value: WeekStart) => { + public onWeekStartChange = (value?: WeekStart) => { this.getTimeRange().setState({ weekStart: value }); }; @@ -258,7 +258,7 @@ export class GeneralSettingsEditView nowDelay={nowDelay || ''} liveNow={liveNow} timezone={timeZone || ''} - weekStart={weekStart || ''} + weekStart={weekStart} /> {/* @todo: Update "Graph tooltip" description to remove prompt about reloading when resolving #46581 */} diff --git a/public/app/features/dashboard/api/ResponseTransformers.ts b/public/app/features/dashboard/api/ResponseTransformers.ts index b57465de211..5ad1d7836d6 100644 --- a/public/app/features/dashboard/api/ResponseTransformers.ts +++ b/public/app/features/dashboard/api/ResponseTransformers.ts @@ -41,7 +41,7 @@ import { GridLayoutItemKind, } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0'; import { DashboardLink, DataTransformerConfig } from '@grafana/schema/src/raw/dashboard/x/dashboard_types.gen'; -import { WeekStart } from '@grafana/ui'; +import { isWeekStart, WeekStart } from '@grafana/ui'; import { AnnoKeyCreatedBy, AnnoKeyDashboardGnetId, @@ -161,8 +161,7 @@ export function ensureV2Response( fiscalYearStartMonth: dashboard.fiscalYearStartMonth || timeSettingsDefaults.fiscalYearStartMonth, hideTimepicker: dashboard.timepicker?.hidden || timeSettingsDefaults.hideTimepicker, quickRanges: dashboard.timepicker?.quick_ranges, - // casting WeekStart here to avoid editing old schema - weekStart: (dashboard.weekStart as WeekStart) || timeSettingsDefaults.weekStart, + weekStart: getWeekStart(dashboard.weekStart, timeSettingsDefaults.weekStart), nowDelay: dashboard.timepicker?.nowDelay || timeSettingsDefaults.nowDelay, }, links: dashboard.links || [], @@ -332,6 +331,13 @@ function isRowPanel(panel: Panel | RowPanel): panel is RowPanel { return panel.type === 'row'; } +function getWeekStart(weekStart?: string, defaultWeekStart?: WeekStart): WeekStart | undefined { + if (!weekStart || !isWeekStart(weekStart)) { + return defaultWeekStart; + } + return weekStart; +} + function buildRowKind(p: RowPanel, elements: GridLayoutItemKind[]): GridLayoutRowKind { return { kind: 'GridLayoutRow', diff --git a/public/app/features/dashboard/components/DashNav/DashNavTimeControls.tsx b/public/app/features/dashboard/components/DashNav/DashNavTimeControls.tsx index 7be88761ec9..6c66c66dc82 100644 --- a/public/app/features/dashboard/components/DashNav/DashNavTimeControls.tsx +++ b/public/app/features/dashboard/components/DashNav/DashNavTimeControls.tsx @@ -3,7 +3,7 @@ import { Unsubscribable } from 'rxjs'; import { dateMath, TimeRange, TimeZone } from '@grafana/data'; import { TimeRangeUpdatedEvent } from '@grafana/runtime'; -import { defaultIntervals, RefreshPicker } from '@grafana/ui'; +import { defaultIntervals, isWeekStart, RefreshPicker } from '@grafana/ui'; import { TimePickerWithHistory } from 'app/core/components/TimePicker/TimePickerWithHistory'; import { appEvents } from 'app/core/core'; import { t } from 'app/core/internationalization'; @@ -121,7 +121,7 @@ export class DashNavTimeControls extends Component { onChangeFiscalYearStartMonth={this.onChangeFiscalYearStartMonth} isOnCanvas={isOnCanvas} onToolbarTimePickerClick={this.props.onToolbarTimePickerClick} - weekStart={weekStart} + weekStart={isWeekStart(weekStart) ? weekStart : undefined} quickRanges={quick_ranges} /> { + const onWeekStartChange = (weekStart?: WeekStart) => { dashboard.weekStart = weekStart; setRenderCounter(renderCounter + 1); updateWeekStart(weekStart); diff --git a/public/app/features/dashboard/components/DashboardSettings/TimePickerSettings.tsx b/public/app/features/dashboard/components/DashboardSettings/TimePickerSettings.tsx index d88e3deaa64..1b31c3ee035 100644 --- a/public/app/features/dashboard/components/DashboardSettings/TimePickerSettings.tsx +++ b/public/app/features/dashboard/components/DashboardSettings/TimePickerSettings.tsx @@ -10,7 +10,7 @@ import { t } from 'app/core/internationalization'; import { AutoRefreshIntervals } from './AutoRefreshIntervals'; interface Props { - onWeekStartChange: (weekStart: WeekStart) => void; + onWeekStartChange: (weekStart?: WeekStart) => void; onTimeZoneChange: (timeZone: TimeZone) => void; onRefreshIntervalChange: (interval: string[]) => void; onNowDelayChange: (nowDelay: string) => void; @@ -20,7 +20,7 @@ interface Props { timePickerHidden?: boolean; nowDelay?: string; timezone: TimeZone; - weekStart: string; + weekStart?: WeekStart; liveNow?: boolean; } @@ -62,7 +62,7 @@ export class TimePickerSettings extends PureComponent { this.props.onTimeZoneChange(timeZone); }; - onWeekStartChange = (weekStart: WeekStart) => { + onWeekStartChange = (weekStart?: WeekStart) => { this.props.onWeekStartChange(weekStart); }; diff --git a/public/app/features/dashboard/state/actions.ts b/public/app/features/dashboard/state/actions.ts index 3f9b8d529f8..ed28663f745 100644 --- a/public/app/features/dashboard/state/actions.ts +++ b/public/app/features/dashboard/state/actions.ts @@ -1,5 +1,6 @@ import { TimeZone } from '@grafana/data'; import { getBackendSrv } from '@grafana/runtime'; +import { WeekStart } from '@grafana/ui'; import { notifyApp } from 'app/core/actions'; import { createSuccessNotification } from 'app/core/copy/appNotification'; import { getDashboardAPI } from 'app/features/dashboard/api/dashboard_api'; @@ -56,7 +57,7 @@ export const updateTimeZoneDashboard = }; export const updateWeekStartDashboard = - (weekStart: string): ThunkResult => + (weekStart?: WeekStart): ThunkResult => (dispatch) => { dispatch(updateWeekStartForSession(weekStart)); getTimeSrv().refreshTimeModel(); diff --git a/public/app/features/dashboard/state/initDashboard.ts b/public/app/features/dashboard/state/initDashboard.ts index 23b36244519..71c5cbf79eb 100644 --- a/public/app/features/dashboard/state/initDashboard.ts +++ b/public/app/features/dashboard/state/initDashboard.ts @@ -273,7 +273,7 @@ export function initDashboard(args: InitDashboardArgs): ThunkResult { } // set week start - if (dashboard.weekStart !== '') { + if (dashboard.weekStart !== '' && dashboard.weekStart !== undefined) { setWeekStart(dashboard.weekStart); } else { setWeekStart(config.bootData.user.weekStart); diff --git a/public/app/features/explore/DrilldownAlertBox.tsx b/public/app/features/explore/DrilldownAlertBox.tsx new file mode 100644 index 00000000000..b6618f3f479 --- /dev/null +++ b/public/app/features/explore/DrilldownAlertBox.tsx @@ -0,0 +1,42 @@ +import { useLocalStorage } from 'react-use'; + +import { Alert, LinkButton, Stack } from '@grafana/ui'; + +import { t, Trans } from '../../core/internationalization'; + +type Props = { + datasourceType: string; +}; + +export function DrilldownAlertBox(props: Props) { + const isDsCompatibleWithDrilldown = ['prometheus', 'loki', 'tempo', 'grafana-pyroscope-datasource'].includes( + props.datasourceType + ); + + const [dismissed, setDismissed] = useLocalStorage('grafana.explore.drilldownsBoxDismissed', false); + + return ( + isDsCompatibleWithDrilldown && + !dismissed && ( + { + setDismissed(true); + }} + > + + + + Looking for the Grafana Explore apps? They are now called the Grafana Drilldown apps and can be found + under Menu > Drilldown + + + + Go to Grafana Drilldown + + + + ) + ); +} diff --git a/public/app/features/explore/Explore.tsx b/public/app/features/explore/Explore.tsx index 4927fc5be4a..7229276849e 100644 --- a/public/app/features/explore/Explore.tsx +++ b/public/app/features/explore/Explore.tsx @@ -23,18 +23,14 @@ import { getDataSourceSrv, reportInteraction } from '@grafana/runtime'; import { DataQuery } from '@grafana/schema'; import { AdHocFilterItem, - Alert, ErrorBoundaryAlert, - LinkButton, PanelContainer, ScrollContainer, - Stack, Themeable2, withTheme2, } from '@grafana/ui'; import { FILTER_FOR_OPERATOR, FILTER_OUT_OPERATOR } from '@grafana/ui/src/components/Table/types'; import { supportedFeatures } from 'app/core/history/richHistoryStorageProvider'; -import { t, Trans } from 'app/core/internationalization'; import { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSource'; import { StoreState } from 'app/types'; @@ -45,6 +41,7 @@ import { ContentOutlineContextProvider } from './ContentOutline/ContentOutlineCo import { ContentOutlineItem } from './ContentOutline/ContentOutlineItem'; import { CorrelationHelper } from './CorrelationHelper'; import { CustomContainer } from './CustomContainer'; +import { DrilldownAlertBox } from './DrilldownAlertBox'; import { ExploreToolbar } from './ExploreToolbar'; import { FlameGraphExploreContainer } from './FlameGraph/FlameGraphExploreContainer'; import { GraphContainer } from './Graph/GraphContainer'; @@ -568,9 +565,6 @@ export class Explore extends PureComponent { if (showCorrelationHelper && correlationEditorHelperData !== undefined) { correlationsBox = ; } - const isDsCompatibleWithDrilldown = ['prometheus', 'loki', 'tempo', 'grafana-pyroscope-datasource'].includes( - datasourceInstance?.type || '' - ); return ( @@ -600,27 +594,7 @@ export class Explore extends PureComponent { <> - {isDsCompatibleWithDrilldown && ( - - - - - Looking for the Grafana Explore apps? They are now called the Grafana Drilldown apps - and can be found under Menu > Drilldown - - - - Go to Grafana Drilldown - - - - )} + {correlationsBox} diff --git a/public/app/features/expressions/components/Threshold.tsx b/public/app/features/expressions/components/Threshold.tsx index 6474c497e16..6d0d43eb7e9 100644 --- a/public/app/features/expressions/components/Threshold.tsx +++ b/public/app/features/expressions/components/Threshold.tsx @@ -5,8 +5,9 @@ import * as React from 'react'; import { FormEvent, useEffect, useReducer } from 'react'; import { GrafanaTheme2, SelectableValue } from '@grafana/data'; -import { InlineField, InlineFieldRow, InlineSwitch, Input, Select, useStyles2, Stack } from '@grafana/ui'; +import { InlineField, InlineFieldRow, InlineSwitch, Input, Select, Stack, useStyles2 } from '@grafana/ui'; import { config } from 'app/core/config'; +import { t } from 'app/core/internationalization'; import { EvalFunction } from 'app/features/alerting/state/alertDef'; import { ClassicCondition, ExpressionQuery, thresholdFunctions } from '../types'; @@ -81,7 +82,9 @@ export const Threshold = ({ labelWidth, onChange, refIds, query, onError, useHys const isRange = conditionInState.evaluator.type === EvalFunction.IsWithinRange || - conditionInState.evaluator.type === EvalFunction.IsOutsideRange; + conditionInState.evaluator.type === EvalFunction.IsOutsideRange || + conditionInState.evaluator.type === EvalFunction.IsOutsideRangeIncluded || + conditionInState.evaluator.type === EvalFunction.IsWithinRangeIncluded; const hysteresisEnabled = Boolean(config.featureToggles?.recoveryThreshold) && useHysteresis; @@ -155,7 +158,7 @@ export const Threshold = ({ labelWidth, onChange, refIds, query, onError, useHys
    - - -
    - - allowOnblur.current && onUnloadValueChange(event, 0)} - defaultValue={condition.unloadEvaluator?.params[0]} - /> - -
    - -
    - - allowOnblur.current && onUnloadValueChange(event, 1)} - defaultValue={condition.unloadEvaluator?.params[1]} - /> - -
    -
    -
    - - ); - } else { - return ( - - - -
    - - allowOnblur.current && onUnloadValueChange(event, 0)} - defaultValue={condition.unloadEvaluator?.params[0]} - /> - -
    + switch (condition.evaluator.type) { + case EvalFunction.IsWithinRange: + if (condition.evaluator.type === EvalFunction.IsWithinRange) { + return ( + + + +
    + + allowOnblur.current && onUnloadValueChange(event, 0)} + defaultValue={condition.unloadEvaluator?.params[0]} + /> + +
    + +
    + + allowOnblur.current && onUnloadValueChange(event, 1)} + defaultValue={condition.unloadEvaluator?.params[1]} + /> + +
    +
    +
    +
    + ); + } + case EvalFunction.IsOutsideRange: + return ( + + + +
    + + allowOnblur.current && onUnloadValueChange(event, 0)} + defaultValue={condition.unloadEvaluator?.params[0]} + /> + +
    - -
    - - allowOnblur.current && onUnloadValueChange(event, 1)} - defaultValue={condition.unloadEvaluator?.params[1]} - /> - -
    -
    -
    -
    - ); + +
    + + allowOnblur.current && onUnloadValueChange(event, 1)} + defaultValue={condition.unloadEvaluator?.params[1]} + /> + +
    +
    +
    +
    + ); + case EvalFunction.IsOutsideRangeIncluded: + return ( + + + +
    + + allowOnblur.current && onUnloadValueChange(event, 0)} + defaultValue={condition.unloadEvaluator?.params[0]} + /> + +
    + +
    + + allowOnblur.current && onUnloadValueChange(event, 1)} + defaultValue={condition.unloadEvaluator?.params[1]} + /> + +
    +
    +
    +
    + ); + case EvalFunction.IsWithinRangeIncluded: + return ( + + + +
    + + allowOnblur.current && onUnloadValueChange(event, 0)} + defaultValue={condition.unloadEvaluator?.params[0]} + /> + +
    + +
    + + allowOnblur.current && onUnloadValueChange(event, 1)} + defaultValue={condition.unloadEvaluator?.params[1]} + /> + +
    +
    +
    +
    + ); + default: + return null; } } function RecoveryForSingleValue({ allowOnblur }: RecoveryProps) { - if (condition.evaluator.type === EvalFunction.IsAbove) { - return ( - - - { - allowOnblur.current && onUnloadValueChange(event, 0); - }} - defaultValue={condition.unloadEvaluator?.params[0]} - /> - - - ); - } else { - return ( - - - { - allowOnblur.current && onUnloadValueChange(event, 0); - }} - defaultValue={condition.unloadEvaluator?.params[0]} - /> - - - ); + switch (condition.evaluator.type) { + case EvalFunction.IsAbove: + return ( + + + { + allowOnblur.current && onUnloadValueChange(event, 0); + }} + defaultValue={condition.unloadEvaluator?.params[0]} + /> + + + ); + case EvalFunction.IsBelow: + return ( + + + { + allowOnblur.current && onUnloadValueChange(event, 0); + }} + defaultValue={condition.unloadEvaluator?.params[0]} + /> + + + ); + case EvalFunction.IsEqual: + return ( + + + { + allowOnblur.current && onUnloadValueChange(event, 0); + }} + defaultValue={condition.unloadEvaluator?.params[0]} + /> + + + ); + case EvalFunction.IsNotEqual: + return ( + + + { + allowOnblur.current && onUnloadValueChange(event, 0); + }} + defaultValue={condition.unloadEvaluator?.params[0]} + /> + + + ); + case EvalFunction.IsGreaterThanEqual: + return ( + + + { + allowOnblur.current && onUnloadValueChange(event, 0); + }} + defaultValue={condition.unloadEvaluator?.params[0]} + /> + + + ); + case EvalFunction.IsLessThanEqual: + return ( + + + { + allowOnblur.current && onUnloadValueChange(event, 0); + }} + defaultValue={condition.unloadEvaluator?.params[0]} + /> + + + ); + default: + return null; } } } diff --git a/public/app/features/expressions/components/thresholdReducer.ts b/public/app/features/expressions/components/thresholdReducer.ts index 7fa1e428a98..503baa3e727 100644 --- a/public/app/features/expressions/components/thresholdReducer.ts +++ b/public/app/features/expressions/components/thresholdReducer.ts @@ -104,12 +104,30 @@ function getUnloadEvaluatorTypeFromEvaluatorType(type: EvalFunction) { if (type === EvalFunction.IsBelow) { return EvalFunction.IsAbove; } + if (type === EvalFunction.IsEqual) { + return EvalFunction.IsNotEqual; + } + if (type === EvalFunction.IsNotEqual) { + return EvalFunction.IsEqual; + } + if (type === EvalFunction.IsGreaterThanEqual) { + return EvalFunction.IsLessThanEqual; + } + if (type === EvalFunction.IsLessThanEqual) { + return EvalFunction.IsGreaterThanEqual; + } if (type === EvalFunction.IsWithinRange) { return EvalFunction.IsOutsideRange; } if (type === EvalFunction.IsOutsideRange) { return EvalFunction.IsWithinRange; } + if (type === EvalFunction.IsWithinRangeIncluded) { + return EvalFunction.IsOutsideRangeIncluded; + } + if (type === EvalFunction.IsOutsideRangeIncluded) { + return EvalFunction.IsWithinRangeIncluded; + } return EvalFunction.IsBelow; } @@ -126,7 +144,12 @@ export function isInvalid(condition: ClassicCondition) { const { type, params: loadParams } = evaluator; const { params: unloadParams } = unloadEvaluator; - if (type === EvalFunction.IsWithinRange || type === EvalFunction.IsOutsideRange) { + if ( + type === EvalFunction.IsWithinRange || + type === EvalFunction.IsOutsideRange || + type === EvalFunction.IsWithinRangeIncluded || + type === EvalFunction.IsOutsideRangeIncluded + ) { if (unloadParams[0] === undefined || Number.isNaN(unloadParams[0])) { return { errorMsgFrom: 'This value cannot be empty' }; } @@ -149,6 +172,26 @@ export function isInvalid(condition: ClassicCondition) { return { errorMsg: `Enter a number more than or equal to ${firstParamInEvaluator}` }; } break; + case EvalFunction.IsEqual: + if (firstParamInUnloadEvaluator === firstParamInEvaluator) { + return { errorMsg: `Enter a different number than ${firstParamInEvaluator}` }; + } + break; + case EvalFunction.IsNotEqual: + if (firstParamInUnloadEvaluator !== firstParamInEvaluator) { + return { errorMsg: `Enter the same number as ${firstParamInEvaluator}` }; + } + break; + case EvalFunction.IsGreaterThanEqual: + if (firstParamInUnloadEvaluator >= firstParamInEvaluator) { + return { errorMsg: `Enter a number less than ${firstParamInEvaluator}` }; + } + break; + case EvalFunction.IsLessThanEqual: + if (firstParamInUnloadEvaluator <= firstParamInEvaluator) { + return { errorMsg: `Enter a number more than ${firstParamInEvaluator}` }; + } + break; case EvalFunction.IsOutsideRange: if (firstParamInUnloadEvaluator < firstParamInEvaluator) { return { errorMsgFrom: `Enter a number more than or equal to ${firstParamInEvaluator}` }; @@ -165,6 +208,22 @@ export function isInvalid(condition: ClassicCondition) { return { errorMsgTo: `Enter a number be more than or equal to ${secondParamInEvaluator}` }; } break; + case EvalFunction.IsOutsideRangeIncluded: + if (firstParamInUnloadEvaluator <= firstParamInEvaluator) { + return { errorMsgFrom: `Enter a number more than ${firstParamInEvaluator}` }; + } + if (secondParamInUnloadEvaluator >= secondParamInEvaluator) { + return { errorMsgTo: `Enter a number less than ${secondParamInEvaluator}` }; + } + break; + case EvalFunction.IsWithinRangeIncluded: + if (firstParamInUnloadEvaluator >= firstParamInEvaluator) { + return { errorMsgFrom: `Enter a number less than ${firstParamInEvaluator}` }; + } + if (secondParamInUnloadEvaluator <= secondParamInEvaluator) { + return { errorMsgTo: `Enter a number be more than ${secondParamInEvaluator}` }; + } + break; default: throw new Error(`evaluator function type ${type} not supported.`); } diff --git a/public/app/features/expressions/types.ts b/public/app/features/expressions/types.ts index a1f88729c1e..a132670f00f 100644 --- a/public/app/features/expressions/types.ts +++ b/public/app/features/expressions/types.ts @@ -126,8 +126,14 @@ export const upsamplingTypes: Array> = [ export const thresholdFunctions: Array> = [ { value: EvalFunction.IsAbove, label: 'Is above' }, { value: EvalFunction.IsBelow, label: 'Is below' }, + { value: EvalFunction.IsEqual, label: 'Is equal to' }, + { value: EvalFunction.IsNotEqual, label: 'Is not equal to' }, + { value: EvalFunction.IsGreaterThanEqual, label: 'Is above or equal to' }, + { value: EvalFunction.IsLessThanEqual, label: 'Is below or equal to' }, { value: EvalFunction.IsWithinRange, label: 'Is within range' }, { value: EvalFunction.IsOutsideRange, label: 'Is outside range' }, + { value: EvalFunction.IsWithinRangeIncluded, label: 'Is within range included' }, + { value: EvalFunction.IsOutsideRangeIncluded, label: 'Is outside range included' }, ]; /** diff --git a/public/app/features/profile/state/reducers.ts b/public/app/features/profile/state/reducers.ts index 5098fa3670d..f4de9c34f0b 100644 --- a/public/app/features/profile/state/reducers.ts +++ b/public/app/features/profile/state/reducers.ts @@ -2,6 +2,7 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { isEmpty, isString, set } from 'lodash'; import { dateTimeFormatTimeAgo, setWeekStart, TimeZone } from '@grafana/data'; +import { getWeekStart, WeekStart } from '@grafana/ui'; import config from 'app/core/config'; import { contextSrv } from 'app/core/core'; import { Team, ThunkResult, UserDTO, UserOrg, UserSession } from 'app/types'; @@ -116,10 +117,10 @@ export const updateTimeZoneForSession = (timeZone: TimeZone): ThunkResult }; }; -export const updateWeekStartForSession = (weekStart: string): ThunkResult => { +export const updateWeekStartForSession = (weekStart?: WeekStart): ThunkResult => { return async (dispatch) => { - if (!isString(weekStart) || isEmpty(weekStart)) { - weekStart = config?.bootData?.user?.weekStart; + if (!weekStart) { + weekStart = getWeekStart(); } set(contextSrv, 'user.weekStart', weekStart); diff --git a/public/app/plugins/panel/histogram/HistogramPanel.tsx b/public/app/plugins/panel/histogram/HistogramPanel.tsx index 2c2805069a8..517f41187fc 100644 --- a/public/app/plugins/panel/histogram/HistogramPanel.tsx +++ b/public/app/plugins/panel/histogram/HistogramPanel.tsx @@ -1,7 +1,7 @@ import { useMemo } from 'react'; -import { PanelProps, buildHistogram, cacheFieldDisplayNames, getHistogramFields } from '@grafana/data'; -import { histogramFieldsToFrame } from '@grafana/data/src/transformations/transformers/histogram'; +import { DataFrameType, PanelProps, buildHistogram, cacheFieldDisplayNames, getHistogramFields } from '@grafana/data'; +import { histogramFieldsToFrame, joinHistograms } from '@grafana/data/src/transformations/transformers/histogram'; import { TooltipDisplayMode, TooltipPlugin2, useTheme2 } from '@grafana/ui'; import { TooltipHoverMode } from '@grafana/ui/src/components/uPlot/plugins/TooltipPlugin2'; @@ -34,13 +34,19 @@ export const HistogramPanel = ({ data, options, width, height }: Props) => { cacheFieldDisplayNames(data.series); - if (data.series.length === 1) { - const info = getHistogramFields(data.series[0]); - if (info) { - return histogramFieldsToFrame(info); + if ( + data.series.length === 1 || + data.series.every( + (frame) => frame.meta?.type === DataFrameType.HeatmapCells || frame.meta?.type === DataFrameType.HeatmapRows + ) + ) { + const histograms = data.series.map((frame) => getHistogramFields(frame)).filter((hist) => hist != null); + + if (histograms.length) { + return histogramFieldsToFrame(joinHistograms(histograms), theme); } } - const hist = buildHistogram(data.series, options); + const hist = buildHistogram(data.series, options, theme); if (!hist) { return undefined; } diff --git a/public/locales/de-DE/grafana.json b/public/locales/de-DE/grafana.json index 1c26fc857cc..93ff994ba79 100644 --- a/public/locales/de-DE/grafana.json +++ b/public/locales/de-DE/grafana.json @@ -528,6 +528,19 @@ }, "pause": { "label": "" + }, + "threshold": { + "recovery": { + "stop-alerting-above": "", + "stop-alerting-bellow": "", + "stop-alerting-equal": "", + "stop-alerting-inside-range": "", + "stop-alerting-less": "", + "stop-alerting-more": "", + "stop-alerting-not-equal": "", + "stop-alerting-outside-range": "", + "title": "" + } } }, "rule-groups": { @@ -810,6 +823,7 @@ "collapse": "", "edit": "", "help": "", + "loading": "", "locale": { "default": "Standard" }, @@ -1043,6 +1057,11 @@ } } }, + "editpane": { + "add": "", + "configure": "", + "outline": "" + }, "empty": { "add-library-panel-body": "Visualisierungen hinzufügen, die mit anderen Dashboards geteilt werden.", "add-library-panel-button": "Bibliotheksfenster hinzufügen", @@ -1180,6 +1199,7 @@ "toolbar": { "add": "Hinzufügen", "add-panel": "", + "add-panel-description": "", "add-panel-lib": "", "add-row": "", "add-tab": "", @@ -1205,6 +1225,7 @@ "label": "", "tooltip": "" }, + "libray-panel-description": "", "mark-favorite": "Als Favorit markieren", "more-save-options": "", "open-original": "Original-Dashboard öffnen", @@ -1213,6 +1234,7 @@ "playlist-stop": "Wiedergabeliste stoppen", "public-dashboard": "", "refresh": "Dashboard aktualisieren", + "row-description": "", "save": "Dashboard speichern", "save-dashboard": { "label": "", @@ -1232,6 +1254,7 @@ "share-button": "Teilen", "show-hidden-elements": "", "switch-old-dashboard": "", + "tabs-description": "", "unlink-library-panel": "", "unmark-favorite": "Markierung als Favorit entfernen" }, @@ -1642,6 +1665,10 @@ "incomplete-request-error": "", "send-custom-feedback": "" }, + "get-enterprise": { + "requires-license": "", + "title": "" + }, "grafana-ui": { "action-editor": { "button": { @@ -2045,6 +2072,7 @@ "render-image-error-description": "" } }, + "lock-icon": "", "login": { "divider": { "connecting-text": "" @@ -2839,6 +2867,7 @@ }, "plugins": { "catalog": { + "no-updates-available": "", "update-all": { "all-plugins-updated": "", "available-header": "", @@ -2898,6 +2927,12 @@ "empty-state": { "message": "" }, + "filter": { + "disabled": "", + "sort": "", + "sort-list": "", + "state": "" + }, "plugin-help": { "error": "", "not-found": "" diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index 305e04488c8..40e28925444 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -528,6 +528,19 @@ }, "pause": { "label": "Pause evaluation" + }, + "threshold": { + "recovery": { + "stop-alerting-above": "Stop alerting when above", + "stop-alerting-bellow": "Stop alerting when below", + "stop-alerting-equal": "Stop alerting when equal to", + "stop-alerting-inside-range": "Stop alerting when inside range", + "stop-alerting-less": "Stop alerting when less than", + "stop-alerting-more": "Stop alerting when more than", + "stop-alerting-not-equal": "Stop alerting when not equal to", + "stop-alerting-outside-range": "Stop alerting when outside range", + "title": "Custom recovery threshold" + } } }, "rule-groups": { @@ -1044,6 +1057,11 @@ } } }, + "editpane": { + "add": "Add", + "configure": "Configure", + "outline": "Outline" + }, "empty": { "add-library-panel-body": "Add visualizations that are shared with other dashboards.", "add-library-panel-button": "Add library panel", @@ -1181,7 +1199,8 @@ "toolbar": { "add": "Add", "add-panel": "Panel", - "add-panel-lib": "Import", + "add-panel-description": "A container for visualizations and other content", + "add-panel-lib": "Import library panel", "add-row": "Row", "add-tab": "Tab", "alert-rules": "Alert rules", @@ -1206,6 +1225,7 @@ "label": "Exit edit", "tooltip": "Exits edit mode and discards unsaved changes" }, + "libray-panel-description": "Libray panels allow you share and reuse panels between dashboards", "mark-favorite": "Mark as favorite", "more-save-options": "More save options", "open-original": "Open original dashboard", @@ -1214,6 +1234,7 @@ "playlist-stop": "Stop playlist", "public-dashboard": "Public", "refresh": "Refresh dashboard", + "row-description": "A group of panels with an optional header", "save": "Save dashboard", "save-dashboard": { "label": "Save dashboard", @@ -1233,6 +1254,7 @@ "share-button": "Share", "show-hidden-elements": "Show hidden", "switch-old-dashboard": "Switch to old dashboard page", + "tabs-description": "Break up your dashboard into different horizontal tabs", "unlink-library-panel": "Unlink library panel", "unmark-favorite": "Unmark as favorite" }, diff --git a/public/locales/es-ES/grafana.json b/public/locales/es-ES/grafana.json index aead0c584e5..a7f1f3424f4 100644 --- a/public/locales/es-ES/grafana.json +++ b/public/locales/es-ES/grafana.json @@ -528,6 +528,19 @@ }, "pause": { "label": "" + }, + "threshold": { + "recovery": { + "stop-alerting-above": "", + "stop-alerting-bellow": "", + "stop-alerting-equal": "", + "stop-alerting-inside-range": "", + "stop-alerting-less": "", + "stop-alerting-more": "", + "stop-alerting-not-equal": "", + "stop-alerting-outside-range": "", + "title": "" + } } }, "rule-groups": { @@ -810,6 +823,7 @@ "collapse": "", "edit": "", "help": "", + "loading": "", "locale": { "default": "Por defecto" }, @@ -1043,6 +1057,11 @@ } } }, + "editpane": { + "add": "", + "configure": "", + "outline": "" + }, "empty": { "add-library-panel-body": "Añadir las visualizaciones que se comparten con otros tableros.", "add-library-panel-button": "Añadir panel de biblioteca", @@ -1180,6 +1199,7 @@ "toolbar": { "add": "Añadir", "add-panel": "", + "add-panel-description": "", "add-panel-lib": "", "add-row": "", "add-tab": "", @@ -1205,6 +1225,7 @@ "label": "", "tooltip": "" }, + "libray-panel-description": "", "mark-favorite": "Marcar como favorito", "more-save-options": "", "open-original": "Abrir el panel de control original", @@ -1213,6 +1234,7 @@ "playlist-stop": "Detener la lista de reproducción", "public-dashboard": "", "refresh": "Actualizar panel de control", + "row-description": "", "save": "Guardar panel de control", "save-dashboard": { "label": "", @@ -1232,6 +1254,7 @@ "share-button": "Compartir", "show-hidden-elements": "", "switch-old-dashboard": "", + "tabs-description": "", "unlink-library-panel": "", "unmark-favorite": "Deshacer marca como favorito" }, @@ -1642,6 +1665,10 @@ "incomplete-request-error": "", "send-custom-feedback": "" }, + "get-enterprise": { + "requires-license": "", + "title": "" + }, "grafana-ui": { "action-editor": { "button": { @@ -2045,6 +2072,7 @@ "render-image-error-description": "" } }, + "lock-icon": "", "login": { "divider": { "connecting-text": "" @@ -2839,6 +2867,7 @@ }, "plugins": { "catalog": { + "no-updates-available": "", "update-all": { "all-plugins-updated": "", "available-header": "", @@ -2898,6 +2927,12 @@ "empty-state": { "message": "" }, + "filter": { + "disabled": "", + "sort": "", + "sort-list": "", + "state": "" + }, "plugin-help": { "error": "", "not-found": "" diff --git a/public/locales/fr-FR/grafana.json b/public/locales/fr-FR/grafana.json index d7bc91e81db..b7d309f71b5 100644 --- a/public/locales/fr-FR/grafana.json +++ b/public/locales/fr-FR/grafana.json @@ -528,6 +528,19 @@ }, "pause": { "label": "" + }, + "threshold": { + "recovery": { + "stop-alerting-above": "", + "stop-alerting-bellow": "", + "stop-alerting-equal": "", + "stop-alerting-inside-range": "", + "stop-alerting-less": "", + "stop-alerting-more": "", + "stop-alerting-not-equal": "", + "stop-alerting-outside-range": "", + "title": "" + } } }, "rule-groups": { @@ -810,6 +823,7 @@ "collapse": "", "edit": "", "help": "", + "loading": "", "locale": { "default": "Par défaut" }, @@ -1043,6 +1057,11 @@ } } }, + "editpane": { + "add": "", + "configure": "", + "outline": "" + }, "empty": { "add-library-panel-body": "Ajoutez des visualisations partagées avec d'autres tableaux de bord.", "add-library-panel-button": "Ajouter un panneau Bibliothèque", @@ -1180,6 +1199,7 @@ "toolbar": { "add": "Ajouter", "add-panel": "", + "add-panel-description": "", "add-panel-lib": "", "add-row": "", "add-tab": "", @@ -1205,6 +1225,7 @@ "label": "", "tooltip": "" }, + "libray-panel-description": "", "mark-favorite": "Marquer comme favori", "more-save-options": "", "open-original": "Ouvrir le tableau de bord d'origine", @@ -1213,6 +1234,7 @@ "playlist-stop": "Arrêter la liste de lecture", "public-dashboard": "", "refresh": "Actualiser le tableau de bord", + "row-description": "", "save": "Enregistrer le tableau de bord", "save-dashboard": { "label": "", @@ -1232,6 +1254,7 @@ "share-button": "Partager", "show-hidden-elements": "", "switch-old-dashboard": "", + "tabs-description": "", "unlink-library-panel": "", "unmark-favorite": "Supprimer des favoris" }, @@ -1642,6 +1665,10 @@ "incomplete-request-error": "", "send-custom-feedback": "" }, + "get-enterprise": { + "requires-license": "", + "title": "" + }, "grafana-ui": { "action-editor": { "button": { @@ -2045,6 +2072,7 @@ "render-image-error-description": "" } }, + "lock-icon": "", "login": { "divider": { "connecting-text": "" @@ -2839,6 +2867,7 @@ }, "plugins": { "catalog": { + "no-updates-available": "", "update-all": { "all-plugins-updated": "", "available-header": "", @@ -2898,6 +2927,12 @@ "empty-state": { "message": "" }, + "filter": { + "disabled": "", + "sort": "", + "sort-list": "", + "state": "" + }, "plugin-help": { "error": "", "not-found": "" diff --git a/public/locales/pseudo-LOCALE/grafana.json b/public/locales/pseudo-LOCALE/grafana.json index daedd5a0375..647da27b6da 100644 --- a/public/locales/pseudo-LOCALE/grafana.json +++ b/public/locales/pseudo-LOCALE/grafana.json @@ -528,6 +528,19 @@ }, "pause": { "label": "Päūşę ęväľūäŧįőʼn" + }, + "threshold": { + "recovery": { + "stop-alerting-above": "Ŝŧőp äľęřŧįʼnģ ŵĥęʼn äþővę", + "stop-alerting-bellow": "Ŝŧőp äľęřŧįʼnģ ŵĥęʼn þęľőŵ", + "stop-alerting-equal": "Ŝŧőp äľęřŧįʼnģ ŵĥęʼn ęqūäľ ŧő", + "stop-alerting-inside-range": "Ŝŧőp äľęřŧįʼnģ ŵĥęʼn įʼnşįđę řäʼnģę", + "stop-alerting-less": "Ŝŧőp äľęřŧįʼnģ ŵĥęʼn ľęşş ŧĥäʼn", + "stop-alerting-more": "Ŝŧőp äľęřŧįʼnģ ŵĥęʼn mőřę ŧĥäʼn", + "stop-alerting-not-equal": "Ŝŧőp äľęřŧįʼnģ ŵĥęʼn ʼnőŧ ęqūäľ ŧő", + "stop-alerting-outside-range": "Ŝŧőp äľęřŧįʼnģ ŵĥęʼn őūŧşįđę řäʼnģę", + "title": "Cūşŧőm řęčővęřy ŧĥřęşĥőľđ" + } } }, "rule-groups": { @@ -1044,6 +1057,11 @@ } } }, + "editpane": { + "add": "Åđđ", + "configure": "Cőʼnƒįģūřę", + "outline": "Øūŧľįʼnę" + }, "empty": { "add-library-panel-body": "Åđđ vįşūäľįžäŧįőʼnş ŧĥäŧ äřę şĥäřęđ ŵįŧĥ őŧĥęř đäşĥþőäřđş.", "add-library-panel-button": "Åđđ ľįþřäřy päʼnęľ", @@ -1181,7 +1199,8 @@ "toolbar": { "add": "Åđđ", "add-panel": "Päʼnęľ", - "add-panel-lib": "Ĩmpőřŧ", + "add-panel-description": "Å čőʼnŧäįʼnęř ƒőř vįşūäľįžäŧįőʼnş äʼnđ őŧĥęř čőʼnŧęʼnŧ", + "add-panel-lib": "Ĩmpőřŧ ľįþřäřy päʼnęľ", "add-row": "Ŗőŵ", "add-tab": "Ŧäþ", "alert-rules": "Åľęřŧ řūľęş", @@ -1206,6 +1225,7 @@ "label": "Ēχįŧ ęđįŧ", "tooltip": "Ēχįŧş ęđįŧ mőđę äʼnđ đįşčäřđş ūʼnşävęđ čĥäʼnģęş" }, + "libray-panel-description": "Ŀįþřäy päʼnęľş äľľőŵ yőū şĥäřę äʼnđ řęūşę päʼnęľş þęŧŵęęʼn đäşĥþőäřđş", "mark-favorite": "Mäřĸ äş ƒävőřįŧę", "more-save-options": "Mőřę şävę őpŧįőʼnş", "open-original": "Øpęʼn őřįģįʼnäľ đäşĥþőäřđ", @@ -1214,6 +1234,7 @@ "playlist-stop": "Ŝŧőp pľäyľįşŧ", "public-dashboard": "Pūþľįč", "refresh": "Ŗęƒřęşĥ đäşĥþőäřđ", + "row-description": "Å ģřőūp őƒ päʼnęľş ŵįŧĥ äʼn őpŧįőʼnäľ ĥęäđęř", "save": "Ŝävę đäşĥþőäřđ", "save-dashboard": { "label": "Ŝävę đäşĥþőäřđ", @@ -1233,6 +1254,7 @@ "share-button": "Ŝĥäřę", "show-hidden-elements": "Ŝĥőŵ ĥįđđęʼn", "switch-old-dashboard": "Ŝŵįŧčĥ ŧő őľđ đäşĥþőäřđ päģę", + "tabs-description": "ßřęäĸ ūp yőūř đäşĥþőäřđ įʼnŧő đįƒƒęřęʼnŧ ĥőřįžőʼnŧäľ ŧäþş", "unlink-library-panel": "Ůʼnľįʼnĸ ľįþřäřy päʼnęľ", "unmark-favorite": "Ůʼnmäřĸ äş ƒävőřįŧę" }, diff --git a/public/locales/pt-BR/grafana.json b/public/locales/pt-BR/grafana.json index d9df30cae3b..32cddf19af3 100644 --- a/public/locales/pt-BR/grafana.json +++ b/public/locales/pt-BR/grafana.json @@ -528,6 +528,19 @@ }, "pause": { "label": "" + }, + "threshold": { + "recovery": { + "stop-alerting-above": "", + "stop-alerting-bellow": "", + "stop-alerting-equal": "", + "stop-alerting-inside-range": "", + "stop-alerting-less": "", + "stop-alerting-more": "", + "stop-alerting-not-equal": "", + "stop-alerting-outside-range": "", + "title": "" + } } }, "rule-groups": { @@ -810,6 +823,7 @@ "collapse": "", "edit": "", "help": "", + "loading": "", "locale": { "default": "Padrão" }, @@ -1043,6 +1057,11 @@ } } }, + "editpane": { + "add": "", + "configure": "", + "outline": "" + }, "empty": { "add-library-panel-body": "Adicione visualizações que são compartilhadas com outros painéis de controle.", "add-library-panel-button": "Adicionar painel de biblioteca", @@ -1180,6 +1199,7 @@ "toolbar": { "add": "Adicionar", "add-panel": "", + "add-panel-description": "", "add-panel-lib": "", "add-row": "", "add-tab": "", @@ -1205,6 +1225,7 @@ "label": "", "tooltip": "" }, + "libray-panel-description": "", "mark-favorite": "Marcar como favorito", "more-save-options": "", "open-original": "Abrir painel de controle original", @@ -1213,6 +1234,7 @@ "playlist-stop": "Parar lista de reprodução", "public-dashboard": "", "refresh": "Atualizar painel de controle", + "row-description": "", "save": "Salvar painel de controle", "save-dashboard": { "label": "", @@ -1232,6 +1254,7 @@ "share-button": "Compartilhar", "show-hidden-elements": "", "switch-old-dashboard": "", + "tabs-description": "", "unlink-library-panel": "", "unmark-favorite": "Desmarcar como favorito" }, @@ -1642,6 +1665,10 @@ "incomplete-request-error": "", "send-custom-feedback": "" }, + "get-enterprise": { + "requires-license": "", + "title": "" + }, "grafana-ui": { "action-editor": { "button": { @@ -2045,6 +2072,7 @@ "render-image-error-description": "" } }, + "lock-icon": "", "login": { "divider": { "connecting-text": "" @@ -2839,6 +2867,7 @@ }, "plugins": { "catalog": { + "no-updates-available": "", "update-all": { "all-plugins-updated": "", "available-header": "", @@ -2898,6 +2927,12 @@ "empty-state": { "message": "" }, + "filter": { + "disabled": "", + "sort": "", + "sort-list": "", + "state": "" + }, "plugin-help": { "error": "", "not-found": "" diff --git a/public/locales/zh-Hans/grafana.json b/public/locales/zh-Hans/grafana.json index 441b75cca69..f51ef704205 100644 --- a/public/locales/zh-Hans/grafana.json +++ b/public/locales/zh-Hans/grafana.json @@ -524,6 +524,19 @@ }, "pause": { "label": "" + }, + "threshold": { + "recovery": { + "stop-alerting-above": "", + "stop-alerting-bellow": "", + "stop-alerting-equal": "", + "stop-alerting-inside-range": "", + "stop-alerting-less": "", + "stop-alerting-more": "", + "stop-alerting-not-equal": "", + "stop-alerting-outside-range": "", + "title": "" + } } }, "rule-groups": { @@ -801,6 +814,7 @@ "collapse": "", "edit": "", "help": "", + "loading": "", "locale": { "default": "默认" }, @@ -1034,6 +1048,11 @@ } } }, + "editpane": { + "add": "", + "configure": "", + "outline": "" + }, "empty": { "add-library-panel-body": "添加与其他仪表板共享的可视化。", "add-library-panel-button": "添加库面板", @@ -1171,6 +1190,7 @@ "toolbar": { "add": "添加", "add-panel": "", + "add-panel-description": "", "add-panel-lib": "", "add-row": "", "add-tab": "", @@ -1196,6 +1216,7 @@ "label": "", "tooltip": "" }, + "libray-panel-description": "", "mark-favorite": "标记为收藏", "more-save-options": "", "open-original": "打开原始仪表板", @@ -1204,6 +1225,7 @@ "playlist-stop": "停止播放列表", "public-dashboard": "", "refresh": "刷新仪表板", + "row-description": "", "save": "保存仪表板", "save-dashboard": { "label": "", @@ -1223,6 +1245,7 @@ "share-button": "分享", "show-hidden-elements": "", "switch-old-dashboard": "", + "tabs-description": "", "unlink-library-panel": "", "unmark-favorite": "取消标记为收藏" }, @@ -1633,6 +1656,10 @@ "incomplete-request-error": "", "send-custom-feedback": "" }, + "get-enterprise": { + "requires-license": "", + "title": "" + }, "grafana-ui": { "action-editor": { "button": { @@ -2035,6 +2062,7 @@ "render-image-error-description": "" } }, + "lock-icon": "", "login": { "divider": { "connecting-text": "" @@ -2829,6 +2857,7 @@ }, "plugins": { "catalog": { + "no-updates-available": "", "update-all": { "all-plugins-updated": "", "available-header": "", @@ -2888,6 +2917,12 @@ "empty-state": { "message": "" }, + "filter": { + "disabled": "", + "sort": "", + "sort-list": "", + "state": "" + }, "plugin-help": { "error": "", "not-found": "" diff --git a/public/openapi3.json b/public/openapi3.json index 3aa7a775761..e5be6cd60ce 100644 --- a/public/openapi3.json +++ b/public/openapi3.json @@ -15316,7 +15316,7 @@ } }, { - "description": "Find annotations for a specified alert.", + "description": "Find annotations for a specified alert rule by its ID.\ndeprecated: AlertID is deprecated and will be removed in future versions. Please use AlertUID instead.", "in": "query", "name": "alertId", "schema": { @@ -15324,6 +15324,14 @@ "type": "integer" } }, + { + "description": "Find annotations for a specified alert rule by its UID.", + "in": "query", + "name": "alertUID", + "schema": { + "type": "string" + } + }, { "description": "Find annotations that are scoped to a specific dashboard", "in": "query",