mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Plugins: Fetch instance provisioned plugins in cloud, to check full installation (#83784)
This commit is contained in:
parent
7b4925ea37
commit
7f970d4887
@ -4,7 +4,15 @@ import { accessControlQueryParam } from 'app/core/utils/accessControl';
|
||||
|
||||
import { API_ROOT, GCOM_API_ROOT, INSTANCE_API_ROOT } from './constants';
|
||||
import { isLocalPluginVisibleByConfig, isRemotePluginVisibleByConfig } from './helpers';
|
||||
import { LocalPlugin, RemotePlugin, CatalogPluginDetails, Version, PluginVersion, InstancePlugin } from './types';
|
||||
import {
|
||||
LocalPlugin,
|
||||
RemotePlugin,
|
||||
CatalogPluginDetails,
|
||||
Version,
|
||||
PluginVersion,
|
||||
InstancePlugin,
|
||||
ProvisionedPlugin,
|
||||
} from './types';
|
||||
|
||||
export async function getPluginDetails(id: string): Promise<CatalogPluginDetails> {
|
||||
const remote = await getRemotePlugin(id);
|
||||
@ -125,6 +133,14 @@ export async function getInstancePlugins(): Promise<InstancePlugin[]> {
|
||||
return instancePlugins;
|
||||
}
|
||||
|
||||
export async function getProvisionedPlugins(): Promise<ProvisionedPlugin[]> {
|
||||
const { items: provisionedPlugins }: { items: Array<{ type: string }> } = await getBackendSrv().get(
|
||||
`${INSTANCE_API_ROOT}/provisioned-plugins`
|
||||
);
|
||||
|
||||
return provisionedPlugins.map((plugin) => ({ slug: plugin.type }));
|
||||
}
|
||||
|
||||
export async function installPlugin(id: string) {
|
||||
// This will install the latest compatible version based on the logic
|
||||
// on the backend.
|
||||
|
@ -112,6 +112,30 @@ describe('Plugins/Helpers', () => {
|
||||
config.featureToggles.managedPluginsInstall = oldFeatureTogglesManagedPluginsInstall;
|
||||
config.pluginAdminExternalManageEnabled = oldPluginAdminExternalManageEnabled;
|
||||
});
|
||||
|
||||
test('plugins should be fully installed if they are installed and it is provisioned', () => {
|
||||
const pluginId = 'plugin-1';
|
||||
|
||||
const oldFeatureTogglesManagedPluginsInstall = config.featureToggles.managedPluginsInstall;
|
||||
const oldPluginAdminExternalManageEnabled = config.pluginAdminExternalManageEnabled;
|
||||
|
||||
config.featureToggles.managedPluginsInstall = true;
|
||||
config.pluginAdminExternalManageEnabled = true;
|
||||
|
||||
const merged = mergeLocalsAndRemotes({
|
||||
local: [...localPlugins, getLocalPluginMock({ id: pluginId })],
|
||||
remote: [...remotePlugins, getRemotePluginMock({ slug: pluginId })],
|
||||
provisioned: [{ slug: pluginId }],
|
||||
});
|
||||
const findMerged = (mergedId: string) => merged.find(({ id }) => id === mergedId);
|
||||
|
||||
expect(merged).toHaveLength(5);
|
||||
expect(findMerged(pluginId)).not.toBeUndefined();
|
||||
expect(findMerged(pluginId)?.isFullyInstalled).toBe(true);
|
||||
|
||||
config.featureToggles.managedPluginsInstall = oldFeatureTogglesManagedPluginsInstall;
|
||||
config.pluginAdminExternalManageEnabled = oldPluginAdminExternalManageEnabled;
|
||||
});
|
||||
});
|
||||
|
||||
describe('mergeLocalAndRemote()', () => {
|
||||
|
@ -7,17 +7,27 @@ import { contextSrv } from 'app/core/core';
|
||||
import { getBackendSrv } from 'app/core/services/backend_srv';
|
||||
import { AccessControlAction } from 'app/types';
|
||||
|
||||
import { CatalogPlugin, InstancePlugin, LocalPlugin, RemotePlugin, RemotePluginStatus, Version } from './types';
|
||||
import {
|
||||
CatalogPlugin,
|
||||
InstancePlugin,
|
||||
LocalPlugin,
|
||||
ProvisionedPlugin,
|
||||
RemotePlugin,
|
||||
RemotePluginStatus,
|
||||
Version,
|
||||
} from './types';
|
||||
|
||||
export function mergeLocalsAndRemotes({
|
||||
local = [],
|
||||
remote = [],
|
||||
instance = [],
|
||||
provisioned = [],
|
||||
pluginErrors: errors,
|
||||
}: {
|
||||
local: LocalPlugin[];
|
||||
remote?: RemotePlugin[];
|
||||
instance?: InstancePlugin[];
|
||||
provisioned?: ProvisionedPlugin[];
|
||||
pluginErrors?: PluginError[];
|
||||
}): CatalogPlugin[] {
|
||||
const catalogPlugins: CatalogPlugin[] = [];
|
||||
@ -28,6 +38,11 @@ export function mergeLocalsAndRemotes({
|
||||
return map;
|
||||
}, new Map<string, InstancePlugin>());
|
||||
|
||||
const provisionedSet = provisioned.reduce((map, provisionedPlugin) => {
|
||||
map.add(provisionedPlugin.slug);
|
||||
return map;
|
||||
}, new Set<string>());
|
||||
|
||||
// add locals
|
||||
local.forEach((localPlugin) => {
|
||||
const remoteCounterpart = remote.find((r) => r.slug === localPlugin.id);
|
||||
@ -51,7 +66,7 @@ export function mergeLocalsAndRemotes({
|
||||
if (configCore.featureToggles.managedPluginsInstall && config.pluginAdminExternalManageEnabled) {
|
||||
catalogPlugin.isFullyInstalled = catalogPlugin.isCore
|
||||
? true
|
||||
: instancesMap.has(remotePlugin.slug) && catalogPlugin.isInstalled;
|
||||
: (instancesMap.has(remotePlugin.slug) || provisionedSet.has(remotePlugin.slug)) && catalogPlugin.isInstalled;
|
||||
|
||||
catalogPlugin.isInstalled = instancesMap.has(remotePlugin.slug) || catalogPlugin.isInstalled;
|
||||
|
||||
|
@ -16,10 +16,11 @@ import {
|
||||
installPlugin,
|
||||
uninstallPlugin,
|
||||
getInstancePlugins,
|
||||
getProvisionedPlugins,
|
||||
} from '../api';
|
||||
import { STATE_PREFIX } from '../constants';
|
||||
import { mapLocalToCatalog, mergeLocalsAndRemotes, updatePanels } from '../helpers';
|
||||
import { CatalogPlugin, RemotePlugin, LocalPlugin, InstancePlugin } from '../types';
|
||||
import { CatalogPlugin, RemotePlugin, LocalPlugin, InstancePlugin, ProvisionedPlugin } from '../types';
|
||||
|
||||
// Fetches
|
||||
export const fetchAll = createAsyncThunk(`${STATE_PREFIX}/fetchAll`, async (_, thunkApi) => {
|
||||
@ -31,6 +32,10 @@ export const fetchAll = createAsyncThunk(`${STATE_PREFIX}/fetchAll`, async (_, t
|
||||
config.pluginAdminExternalManageEnabled && configCore.featureToggles.managedPluginsInstall
|
||||
? from(getInstancePlugins())
|
||||
: of(undefined);
|
||||
const provisioned$ =
|
||||
config.pluginAdminExternalManageEnabled && configCore.featureToggles.managedPluginsInstall
|
||||
? from(getProvisionedPlugins())
|
||||
: of(undefined);
|
||||
const TIMEOUT = 500;
|
||||
const pluginErrors$ = from(getPluginErrors());
|
||||
const local$ = from(getLocalPlugins());
|
||||
@ -48,6 +53,7 @@ export const fetchAll = createAsyncThunk(`${STATE_PREFIX}/fetchAll`, async (_, t
|
||||
local: local$,
|
||||
remote: remote$,
|
||||
instance: instance$,
|
||||
provisioned: provisioned$,
|
||||
pluginErrors: pluginErrors$,
|
||||
})
|
||||
.pipe(
|
||||
@ -66,13 +72,21 @@ export const fetchAll = createAsyncThunk(`${STATE_PREFIX}/fetchAll`, async (_, t
|
||||
if (remote.length > 0) {
|
||||
const local = await lastValueFrom(local$);
|
||||
const instance = await lastValueFrom(instance$);
|
||||
const provisioned = await lastValueFrom(provisioned$);
|
||||
const pluginErrors = await lastValueFrom(pluginErrors$);
|
||||
|
||||
thunkApi.dispatch(addPlugins(mergeLocalsAndRemotes({ local, remote, instance, pluginErrors })));
|
||||
thunkApi.dispatch(
|
||||
addPlugins(mergeLocalsAndRemotes({ local, remote, instance, provisioned, pluginErrors }))
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return forkJoin({ local: local$, instance: instance$, pluginErrors: pluginErrors$ });
|
||||
return forkJoin({
|
||||
local: local$,
|
||||
instance: instance$,
|
||||
provisioned: provisioned$,
|
||||
pluginErrors: pluginErrors$,
|
||||
});
|
||||
},
|
||||
})
|
||||
)
|
||||
@ -81,18 +95,22 @@ export const fetchAll = createAsyncThunk(`${STATE_PREFIX}/fetchAll`, async (_, t
|
||||
local,
|
||||
remote,
|
||||
instance,
|
||||
provisioned,
|
||||
pluginErrors,
|
||||
}: {
|
||||
local: LocalPlugin[];
|
||||
remote?: RemotePlugin[];
|
||||
instance?: InstancePlugin[];
|
||||
provisioned?: ProvisionedPlugin[];
|
||||
pluginErrors: PluginError[];
|
||||
}) => {
|
||||
// Both local and remote plugins are loaded
|
||||
if (local && remote) {
|
||||
thunkApi.dispatch({ type: `${STATE_PREFIX}/fetchLocal/fulfilled` });
|
||||
thunkApi.dispatch({ type: `${STATE_PREFIX}/fetchRemote/fulfilled` });
|
||||
thunkApi.dispatch(addPlugins(mergeLocalsAndRemotes({ local, remote, instance, pluginErrors })));
|
||||
thunkApi.dispatch(
|
||||
addPlugins(mergeLocalsAndRemotes({ local, remote, instance, provisioned, pluginErrors }))
|
||||
);
|
||||
|
||||
// Only remote plugins are loaded (remote timed out)
|
||||
} else if (local) {
|
||||
|
@ -322,3 +322,7 @@ export type InstancePlugin = {
|
||||
pluginSlug: string;
|
||||
version: string;
|
||||
};
|
||||
|
||||
export type ProvisionedPlugin = {
|
||||
slug: string;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user