Merge remote-tracking branch 'origin/main' into bugfix/files-authorization

This commit is contained in:
Roberto Jimenez Sanchez
2025-12-15 16:13:48 +01:00
9 changed files with 74 additions and 66 deletions
@@ -21,11 +21,28 @@ weight: 120
# Install a plugin
Besides the UI, you can use alternative methods to install a plugin depending on your environment or set-up.
{{< admonition type="note" >}}
Installing plugins from the Grafana website into a Grafana Cloud instance will be removed in February 2026.
If you're a Grafana Cloud user, follow [Install a plugin through the Grafana UI](#install-a-plugin-through-the-grafana-uiinstall-a-plugin-through-the-grafana-ui) instead.
{{< /admonition >}}
## Install a plugin through the Grafana UI
The most common way to install a plugin is through the Grafana UI.
1. In Grafana, click **Administration > Plugins and data > Plugins** in the side navigation menu to view all plugins.
1. Browse and find a plugin.
1. Click the plugin's logo.
1. Click **Install**.
You can use use the following alternative methods to install a plugin depending on your environment or setup.
## Install a plugin using Grafana CLI
The Grafana CLI allows you to install, upgrade, and manage your Grafana plugins using a command line tool. For more information about Grafana CLI plugin commands, refer to [Plugin commands](/docs/grafana/<GRAFANA_VERSION>/cli/#plugins-commands).
The Grafana CLI allows you to install, upgrade, and manage your Grafana plugins using a command line tool. For more information about Grafana CLI plugin commands, refer to [Plugin commands](https://grafana.com/docs/grafana/<GRAFANA_VERSION>/administration/cli/#plugins-commands).
## Install a plugin from a ZIP file
@@ -24,7 +24,7 @@ Before you begin, you should have the following available:
- Administrator permissions in your Grafana instance; for more information on assigning Grafana RBAC roles, refer to [Assign RBAC roles](/docs/grafana-cloud/security-and-account-management/authentication-and-permissions/access-control/assign-rbac-roles/).
{{< admonition type="note" >}}
All of the following Terraform configuration files should be saved in the same directory.
Save all of the following Terraform configuration files in the same directory.
{{< /admonition >}}
## Configure the Grafana provider
@@ -658,10 +658,6 @@ const injectedRtkApi = api
query: (queryArg) => ({ url: `/dashboards/db`, method: 'POST', body: queryArg.saveDashboardCommand }),
invalidatesTags: ['dashboards'],
}),
getHomeDashboard: build.query<GetHomeDashboardApiResponse, GetHomeDashboardApiArg>({
query: () => ({ url: `/dashboards/home` }),
providesTags: ['dashboards'],
}),
importDashboard: build.mutation<ImportDashboardApiResponse, ImportDashboardApiArg>({
query: (queryArg) => ({ url: `/dashboards/import`, method: 'POST', body: queryArg.importDashboardRequest }),
invalidatesTags: ['dashboards'],
@@ -2574,8 +2570,6 @@ export type PostDashboardApiResponse = /** status 200 (empty) */ {
export type PostDashboardApiArg = {
saveDashboardCommand: SaveDashboardCommand;
};
export type GetHomeDashboardApiResponse = /** status 200 (empty) */ GetHomeDashboardResponse;
export type GetHomeDashboardApiArg = void;
export type ImportDashboardApiResponse =
/** status 200 (empty) */ ImportDashboardResponseResponseObjectReturnedWhenImportingADashboard;
export type ImportDashboardApiArg = {
@@ -4399,51 +4393,6 @@ export type SaveDashboardCommand = {
overwrite?: boolean;
userId?: number;
};
export type AnnotationActions = {
canAdd?: boolean;
canDelete?: boolean;
canEdit?: boolean;
};
export type AnnotationPermission = {
dashboard?: AnnotationActions;
organization?: AnnotationActions;
};
export type DashboardMeta = {
annotationsPermissions?: AnnotationPermission;
apiVersion?: string;
canAdmin?: boolean;
canDelete?: boolean;
canEdit?: boolean;
canSave?: boolean;
canStar?: boolean;
created?: string;
createdBy?: string;
expires?: string;
/** Deprecated: use FolderUID instead */
folderId?: number;
folderTitle?: string;
folderUid?: string;
folderUrl?: string;
hasAcl?: boolean;
isFolder?: boolean;
isSnapshot?: boolean;
isStarred?: boolean;
provisioned?: boolean;
provisionedExternalId?: string;
publicDashboardEnabled?: boolean;
slug?: string;
type?: string;
updated?: string;
updatedBy?: string;
url?: string;
version?: number;
};
export type GetHomeDashboardResponse = {
dashboard?: Json;
meta?: DashboardMeta;
} & {
redirectUri?: string;
};
export type ImportDashboardResponseResponseObjectReturnedWhenImportingADashboard = {
dashboardId?: number;
description?: string;
@@ -4535,6 +4484,45 @@ export type PublicDashboardDto = {
timeSelectionEnabled?: boolean;
uid?: string;
};
export type AnnotationActions = {
canAdd?: boolean;
canDelete?: boolean;
canEdit?: boolean;
};
export type AnnotationPermission = {
dashboard?: AnnotationActions;
organization?: AnnotationActions;
};
export type DashboardMeta = {
annotationsPermissions?: AnnotationPermission;
apiVersion?: string;
canAdmin?: boolean;
canDelete?: boolean;
canEdit?: boolean;
canSave?: boolean;
canStar?: boolean;
created?: string;
createdBy?: string;
expires?: string;
/** Deprecated: use FolderUID instead */
folderId?: number;
folderTitle?: string;
folderUid?: string;
folderUrl?: string;
hasAcl?: boolean;
isFolder?: boolean;
isSnapshot?: boolean;
isStarred?: boolean;
provisioned?: boolean;
provisionedExternalId?: string;
publicDashboardEnabled?: boolean;
slug?: string;
type?: string;
updated?: string;
updatedBy?: string;
url?: string;
version?: number;
};
export type DashboardFullWithMeta = {
dashboard?: Json;
meta?: DashboardMeta;
@@ -6619,8 +6607,6 @@ export const {
useSearchDashboardSnapshotsQuery,
useLazySearchDashboardSnapshotsQuery,
usePostDashboardMutation,
useGetHomeDashboardQuery,
useLazyGetHomeDashboardQuery,
useImportDashboardMutation,
useInterpolateDashboardMutation,
useListPublicDashboardsQuery,
+3 -1
View File
@@ -493,7 +493,9 @@ func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.S
// swagger:route GET /dashboards/home dashboards getHomeDashboard
//
// Get home dashboard.
// NOTE: the home dashboard is configured in preferences. This API will be removed in G13
//
// Deprecated: true
//
// Responses:
// 200: getHomeDashboardResponse
@@ -40,7 +40,7 @@ func NewResourcePermissionsAuthorizer(
return &ResourcePermissionsAuthorizer{
accessClient: accessClient,
parentProvider: parentProvider,
logger: log.New("iam.resource-permissions-authorizer"),
logger: log.New("iam.authorizer.resource-permissions"),
}
}
@@ -216,8 +216,7 @@ func (r *ResourcePermissionsAuthorizer) FilterList(ctx context.Context, list run
// Skip item on error fetching parent
r.logger.Warn("filter list: error fetching parent, skipping item",
"error", err.Error(),
"namespace",
item.Namespace,
"namespace", item.Namespace,
"group", target.ApiGroup,
"resource", target.Resource,
"name", target.Name,
+4 -2
View File
@@ -21,6 +21,7 @@ import (
"k8s.io/kube-openapi/pkg/spec3"
"k8s.io/kube-openapi/pkg/validation/spec"
"github.com/grafana/authlib/authn"
"github.com/grafana/authlib/types"
iamv0 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1"
@@ -142,6 +143,8 @@ func NewAPIService(
features featuremgmt.FeatureToggles,
zClient zanzana.Client,
reg prometheus.Registerer,
tokenExchanger authn.TokenExchanger,
authorizerDialConfigs map[schema.GroupResource]iamauthorizer.DialConfig,
) *IdentityAccessManagementAPIBuilder {
store := legacy.NewLegacySQLStores(dbProvider)
resourcePermissionsStorage := resourcepermission.ProvideStorageBackend(dbProvider)
@@ -150,9 +153,8 @@ func NewAPIService(
resourceAuthorizer := gfauthorizer.NewResourceAuthorizer(accessClient)
coreRoleAuthorizer := iamauthorizer.NewCoreRoleAuthorizer(accessClient)
// TODO: in a follow up PR, make this configurable
resourceParentProvider := iamauthorizer.NewApiParentProvider(
iamauthorizer.NewRemoteConfigProvider(map[schema.GroupResource]iamauthorizer.DialConfig{}, nil),
iamauthorizer.NewRemoteConfigProvider(authorizerDialConfigs, tokenExchanger),
iamauthorizer.Versions,
)
+2 -1
View File
@@ -3402,11 +3402,12 @@
},
"/dashboards/home": {
"get": {
"description": "NOTE: the home dashboard is configured in preferences. This API will be removed in G13",
"tags": [
"dashboards"
],
"summary": "Get home dashboard.",
"operationId": "getHomeDashboard",
"deprecated": true,
"responses": {
"200": {
"$ref": "#/responses/getHomeDashboardResponse"
@@ -76,12 +76,12 @@ export function DashboardEditPaneRenderer({ editPane, dashboard, isDocked }: Pro
data-testid={selectors.pages.Dashboard.Sidebar.optionsButton}
active={selectedObject === dashboard ? true : false}
/>
<Sidebar.Button
{/* <Sidebar.Button
tooltip={t('dashboard.sidebar.edit-schema.tooltip', 'Edit as code')}
title={t('dashboard.sidebar.edit-schema.title', 'Code')}
icon="brackets-curly"
onClick={() => dashboard.openV2SchemaEditor()}
/>
/> */}
<Sidebar.Divider />
</>
)}
+2 -1
View File
@@ -17651,6 +17651,8 @@
},
"/dashboards/home": {
"get": {
"deprecated": true,
"description": "NOTE: the home dashboard is configured in preferences. This API will be removed in G13",
"operationId": "getHomeDashboard",
"responses": {
"200": {
@@ -17663,7 +17665,6 @@
"$ref": "#/components/responses/internalServerError"
}
},
"summary": "Get home dashboard.",
"tags": [
"dashboards"
]