mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Disable selecting enterprise plugins with no license (#28758)
* Add unlicensed property to plugins * Disable selecting unlicensed plugin * Add customizable plugin market place url * License: workaround enabled only in enterprise * linter * Move licensing info to front end * Update pkg/services/licensing/oss.go Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com> * Update pkg/services/licensing/oss.go Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com> * Update pkg/setting/setting.go Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com> * Update pkg/setting/setting.go Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com> * Update pkg/api/frontendsettings.go Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com> * Update sample.ini * Update docs * Update packages/grafana-runtime/src/config.ts Co-authored-by: Torkel Ödegaard <torkel@grafana.org> * Update public/app/features/datasources/state/buildCategories.ts Co-authored-by: Torkel Ödegaard <torkel@grafana.org> * Update pkg/api/frontendsettings.go Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com> * Update pkg/setting/setting.go Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix spelling Co-authored-by: Leonard Gram <leo@xlson.com> Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.org>
This commit is contained in:
@@ -671,7 +671,7 @@ disable_total_stats = false
|
||||
basic_auth_username =
|
||||
basic_auth_password =
|
||||
|
||||
# Metrics environment info adds dimensions to the `grafana_environment_info` metric, which
|
||||
# Metrics environment info adds dimensions to the `grafana_environment_info` metric, which
|
||||
# can expose more information about the Grafana instance.
|
||||
[metrics.environment_info]
|
||||
#exampleLabel1 = exampleValue1
|
||||
@@ -769,6 +769,7 @@ enable_alpha = false
|
||||
app_tls_skip_verify_insecure = false
|
||||
# Enter a comma-separated list of plugin identifiers to identify plugins that are allowed to be loaded even if they lack a valid signature.
|
||||
allow_loading_unsigned_plugins =
|
||||
marketplace_url = https://grafana.com/grafana/plugins/
|
||||
|
||||
#################################### Grafana Image Renderer Plugin ##########################
|
||||
[plugin.grafana-image-renderer]
|
||||
|
||||
@@ -665,7 +665,7 @@
|
||||
; basic_auth_username =
|
||||
; basic_auth_password =
|
||||
|
||||
# Metrics environment info adds dimensions to the `grafana_environment_info` metric, which
|
||||
# Metrics environment info adds dimensions to the `grafana_environment_info` metric, which
|
||||
# can expose more information about the Grafana instance.
|
||||
[metrics.environment_info]
|
||||
#exampleLabel1 = exampleValue1
|
||||
@@ -757,6 +757,7 @@
|
||||
;app_tls_skip_verify_insecure = false
|
||||
# Enter a comma-separated list of plugin identifiers to identify plugins that are allowed to be loaded even if they lack a valid signature.
|
||||
;allow_loading_unsigned_plugins =
|
||||
;marketplace_url = https://grafana.com/grafana/plugins/
|
||||
|
||||
#################################### Grafana Image Renderer Plugin ##########################
|
||||
[plugin.grafana-image-renderer]
|
||||
|
||||
@@ -1336,6 +1336,10 @@ Set to `true` if you want to test alpha plugins that are not yet ready for gener
|
||||
|
||||
Enter a comma-separated list of plugin identifiers to identify plugins that are allowed to be loaded even if they lack a valid signature.
|
||||
|
||||
### marketplace_url
|
||||
|
||||
Custom install/learn more url for enterprise plugins. Defaults to https://grafana.com/grafana/plugins/.
|
||||
|
||||
<hr>
|
||||
|
||||
## [plugin.grafana-image-renderer]
|
||||
|
||||
@@ -55,6 +55,8 @@ export interface LicenseInfo {
|
||||
expiry: number;
|
||||
licenseUrl: string;
|
||||
stateInfo: string;
|
||||
hasValidLicense: boolean;
|
||||
edition: string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -114,6 +114,7 @@ export interface DataSourcePluginMeta<T extends KeyValue = {}> extends PluginMet
|
||||
queryOptions?: PluginMetaQueryOptions;
|
||||
sort?: number;
|
||||
streaming?: boolean;
|
||||
unlicensed?: boolean;
|
||||
}
|
||||
|
||||
interface PluginMetaQueryOptions {
|
||||
|
||||
@@ -62,6 +62,7 @@ export class GrafanaBootConfig implements GrafanaConfig {
|
||||
rendererAvailable = false;
|
||||
http2Enabled = false;
|
||||
dateFormats?: SystemDateFormatSettings;
|
||||
marketplaceUrl?: string;
|
||||
|
||||
constructor(options: GrafanaBootConfig) {
|
||||
this.theme = options.bootData.user.lightTheme ? getTheme(GrafanaThemeType.Light) : getTheme(GrafanaThemeType.Dark);
|
||||
|
||||
@@ -230,14 +230,17 @@ func (hs *HTTPServer) getFrontendSettingsMap(c *models.ReqContext) (map[string]i
|
||||
"isEnterprise": hs.License.HasValidLicense(),
|
||||
},
|
||||
"licenseInfo": map[string]interface{}{
|
||||
"hasLicense": hs.License.HasLicense(),
|
||||
"expiry": hs.License.Expiry(),
|
||||
"stateInfo": hs.License.StateInfo(),
|
||||
"licenseUrl": hs.License.LicenseURL(c.SignedInUser),
|
||||
"hasLicense": hs.License.HasLicense(),
|
||||
"hasValidLicense": hs.License.HasValidLicense(),
|
||||
"expiry": hs.License.Expiry(),
|
||||
"stateInfo": hs.License.StateInfo(),
|
||||
"licenseUrl": hs.License.LicenseURL(c.SignedInUser),
|
||||
"edition": hs.License.Edition(),
|
||||
},
|
||||
"featureToggles": hs.Cfg.FeatureToggles,
|
||||
"rendererAvailable": hs.RenderService.IsAvailable(),
|
||||
"http2Enabled": hs.Cfg.Protocol == setting.HTTP2Scheme,
|
||||
"marketplaceUrl": hs.Cfg.MarketplaceURL,
|
||||
}
|
||||
|
||||
return jsonObj, nil
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
|
||||
@@ -7,6 +7,10 @@ import (
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
const (
|
||||
openSource = "Open Source"
|
||||
)
|
||||
|
||||
type OSSLicensingService struct {
|
||||
Cfg *setting.Cfg `inject:""`
|
||||
HooksService *hooks.HooksService `inject:""`
|
||||
@@ -21,7 +25,7 @@ func (*OSSLicensingService) Expiry() int64 {
|
||||
}
|
||||
|
||||
func (*OSSLicensingService) Edition() string {
|
||||
return "Open Source"
|
||||
return openSource
|
||||
}
|
||||
|
||||
func (*OSSLicensingService) StateInfo() string {
|
||||
|
||||
@@ -271,6 +271,7 @@ type Cfg struct {
|
||||
PluginsAppsSkipVerifyTLS bool
|
||||
PluginSettings PluginSettings
|
||||
PluginsAllowUnsigned []string
|
||||
MarketplaceURL string
|
||||
DisableSanitizeHtml bool
|
||||
EnterpriseLicensePath string
|
||||
|
||||
@@ -794,6 +795,7 @@ func (cfg *Cfg) Load(args *CommandLineArgs) error {
|
||||
plug = strings.TrimSpace(plug)
|
||||
cfg.PluginsAllowUnsigned = append(cfg.PluginsAllowUnsigned, plug)
|
||||
}
|
||||
cfg.MarketplaceURL = pluginsSection.Key("marketplace_url").MustString("https://grafana.com/grafana/plugins/")
|
||||
cfg.Protocol = Protocol
|
||||
|
||||
// Read and populate feature toggles list
|
||||
|
||||
@@ -129,10 +129,9 @@ interface DataSourceTypeCardProps {
|
||||
const DataSourceTypeCard: FC<DataSourceTypeCardProps> = props => {
|
||||
const { plugin, onLearnMoreClick } = props;
|
||||
const isPhantom = plugin.module === 'phantom';
|
||||
const onClick = !isPhantom ? props.onClick : () => {};
|
||||
|
||||
const onClick = !isPhantom && !plugin.unlicensed ? props.onClick : () => {};
|
||||
// find first plugin info link
|
||||
const learnMoreLink = plugin.info.links && plugin.info.links.length > 0 ? plugin.info.links[0] : null;
|
||||
const learnMoreLink = plugin.info?.links?.length > 0 ? plugin.info.links[0] : null;
|
||||
|
||||
return (
|
||||
<Card
|
||||
@@ -154,7 +153,7 @@ const DataSourceTypeCard: FC<DataSourceTypeCardProps> = props => {
|
||||
{learnMoreLink.name}
|
||||
</LinkButton>
|
||||
)}
|
||||
{!isPhantom && <Button>Select</Button>}
|
||||
{!isPhantom && <Button disabled={plugin.unlicensed}>Select</Button>}
|
||||
</>
|
||||
}
|
||||
labels={
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { DataSourcePluginMeta, PluginType } from '@grafana/data';
|
||||
import { DataSourcePluginCategory } from 'app/types';
|
||||
import { config } from '../../../core/config';
|
||||
|
||||
export function buildCategories(plugins: DataSourcePluginMeta[]): DataSourcePluginCategory[] {
|
||||
const categories: DataSourcePluginCategory[] = [
|
||||
@@ -22,10 +23,15 @@ export function buildCategories(plugins: DataSourcePluginMeta[]): DataSourcePlug
|
||||
categoryIndex[category.id] = category;
|
||||
}
|
||||
|
||||
const { edition, hasValidLicense } = config.licenseInfo;
|
||||
|
||||
for (const plugin of plugins) {
|
||||
const enterprisePlugin = enterprisePlugins.find(item => item.id === plugin.id);
|
||||
// Force category for enterprise plugins
|
||||
if (plugin.enterprise || enterprisePlugins.find(item => item.id === plugin.id)) {
|
||||
if (plugin.enterprise || enterprisePlugin) {
|
||||
plugin.category = 'enterprise';
|
||||
plugin.unlicensed = edition !== 'Open Source' && !hasValidLicense;
|
||||
plugin.info.links = enterprisePlugin?.info?.links || plugin.info.links;
|
||||
}
|
||||
|
||||
// Fix link name
|
||||
@@ -197,7 +203,7 @@ function getPhantomPlugin(options: GetPhantomPluginOptions): DataSourcePluginMet
|
||||
author: { name: 'Grafana Labs' },
|
||||
links: [
|
||||
{
|
||||
url: 'https://grafana.com/grafana/plugins/' + options.id,
|
||||
url: config.marketplaceUrl + options.id,
|
||||
name: 'Install now',
|
||||
},
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user