mirror of https://github.com/grafana/grafana.git
Licensing service (#19903)
* Licensing: supplies a service to handle licensing information * Licensing: uses the license service further Uses the license service instead of settings.isEnterprise: - external team members - saml - usage stats * Licensing: fixes broken tests due to new Licensing service dependency * Licensing: fixes linting errors * Licensing: exposes license expiry information to the frontend
This commit is contained in:
parent
0ecc9a57f1
commit
992b4b8adf
|
|
@ -154,7 +154,7 @@ func (hs *HTTPServer) registerRoutes() {
|
||||||
teamsRoute.Post("/", bind(models.CreateTeamCommand{}), Wrap(hs.CreateTeam))
|
teamsRoute.Post("/", bind(models.CreateTeamCommand{}), Wrap(hs.CreateTeam))
|
||||||
teamsRoute.Put("/:teamId", bind(models.UpdateTeamCommand{}), Wrap(hs.UpdateTeam))
|
teamsRoute.Put("/:teamId", bind(models.UpdateTeamCommand{}), Wrap(hs.UpdateTeam))
|
||||||
teamsRoute.Delete("/:teamId", Wrap(hs.DeleteTeamByID))
|
teamsRoute.Delete("/:teamId", Wrap(hs.DeleteTeamByID))
|
||||||
teamsRoute.Get("/:teamId/members", Wrap(GetTeamMembers))
|
teamsRoute.Get("/:teamId/members", Wrap(hs.GetTeamMembers))
|
||||||
teamsRoute.Post("/:teamId/members", bind(models.AddTeamMemberCommand{}), Wrap(hs.AddTeamMember))
|
teamsRoute.Post("/:teamId/members", bind(models.AddTeamMemberCommand{}), Wrap(hs.AddTeamMember))
|
||||||
teamsRoute.Put("/:teamId/members/:userId", bind(models.UpdateTeamMemberCommand{}), Wrap(hs.UpdateTeamMember))
|
teamsRoute.Put("/:teamId/members/:userId", bind(models.UpdateTeamMemberCommand{}), Wrap(hs.UpdateTeamMember))
|
||||||
teamsRoute.Delete("/:teamId/members/:userId", Wrap(hs.RemoveTeamMember))
|
teamsRoute.Delete("/:teamId/members/:userId", Wrap(hs.RemoveTeamMember))
|
||||||
|
|
|
||||||
|
|
@ -196,7 +196,11 @@ func (hs *HTTPServer) getFrontendSettingsMap(c *m.ReqContext) (map[string]interf
|
||||||
"latestVersion": plugins.GrafanaLatestVersion,
|
"latestVersion": plugins.GrafanaLatestVersion,
|
||||||
"hasUpdate": plugins.GrafanaHasUpdate,
|
"hasUpdate": plugins.GrafanaHasUpdate,
|
||||||
"env": setting.Env,
|
"env": setting.Env,
|
||||||
"isEnterprise": setting.IsEnterprise,
|
"isEnterprise": hs.License.HasValidLicense(),
|
||||||
|
},
|
||||||
|
"licenseInfo": map[string]interface{}{
|
||||||
|
"hasLicense": hs.License.HasLicense(),
|
||||||
|
"expiry": hs.License.Expiry(),
|
||||||
},
|
},
|
||||||
"featureToggles": hs.Cfg.FeatureToggles,
|
"featureToggles": hs.Cfg.FeatureToggles,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,7 @@ type HTTPServer struct {
|
||||||
RemoteCacheService *remotecache.RemoteCache `inject:""`
|
RemoteCacheService *remotecache.RemoteCache `inject:""`
|
||||||
ProvisioningService ProvisioningService `inject:""`
|
ProvisioningService ProvisioningService `inject:""`
|
||||||
Login *login.LoginService `inject:""`
|
Login *login.LoginService `inject:""`
|
||||||
|
License models.Licensing `inject:""`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hs *HTTPServer) Init() error {
|
func (hs *HTTPServer) Init() error {
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ func (hs *HTTPServer) setIndexViewData(c *m.ReqContext) (*dtos.IndexViewData, er
|
||||||
NewGrafanaVersion: plugins.GrafanaLatestVersion,
|
NewGrafanaVersion: plugins.GrafanaLatestVersion,
|
||||||
NewGrafanaVersionExists: plugins.GrafanaHasUpdate,
|
NewGrafanaVersionExists: plugins.GrafanaHasUpdate,
|
||||||
AppName: setting.ApplicationName,
|
AppName: setting.ApplicationName,
|
||||||
AppNameBodyClass: getAppNameBodyClass(setting.ApplicationName),
|
AppNameBodyClass: getAppNameBodyClass(hs.License.HasValidLicense()),
|
||||||
}
|
}
|
||||||
|
|
||||||
if setting.DisableGravatar {
|
if setting.DisableGravatar {
|
||||||
|
|
@ -372,13 +372,10 @@ func (hs *HTTPServer) NotFoundHandler(c *m.ReqContext) {
|
||||||
c.HTML(404, "index", data)
|
c.HTML(404, "index", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAppNameBodyClass(name string) string {
|
func getAppNameBodyClass(validLicense bool) string {
|
||||||
switch name {
|
if validLicense {
|
||||||
case setting.APP_NAME:
|
|
||||||
return "app-grafana"
|
|
||||||
case setting.APP_NAME_ENTERPRISE:
|
|
||||||
return "app-enterprise"
|
return "app-enterprise"
|
||||||
default:
|
|
||||||
return ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return "app-grafana"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ func (hs *HTTPServer) LoginView(c *models.ReqContext) {
|
||||||
}
|
}
|
||||||
|
|
||||||
viewData.Settings["oauth"] = enabledOAuths
|
viewData.Settings["oauth"] = enabledOAuths
|
||||||
viewData.Settings["samlEnabled"] = setting.IsEnterprise && hs.Cfg.SAMLEnabled
|
viewData.Settings["samlEnabled"] = hs.License.HasValidLicense() && hs.Cfg.SAMLEnabled
|
||||||
|
|
||||||
if loginError, ok := tryGetEncryptedCookie(c, LoginErrorCookieName); ok {
|
if loginError, ok := tryGetEncryptedCookie(c, LoginErrorCookieName); ok {
|
||||||
//this cookie is only set whenever an OAuth login fails
|
//this cookie is only set whenever an OAuth login fails
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,8 @@ func TestLoginErrorCookieApiEndpoint(t *testing.T) {
|
||||||
|
|
||||||
sc := setupScenarioContext("/login")
|
sc := setupScenarioContext("/login")
|
||||||
hs := &HTTPServer{
|
hs := &HTTPServer{
|
||||||
Cfg: setting.NewCfg(),
|
Cfg: setting.NewCfg(),
|
||||||
|
License: models.OSSLicensingService{},
|
||||||
}
|
}
|
||||||
|
|
||||||
sc.defaultHandler = Wrap(func(w http.ResponseWriter, c *models.ReqContext) {
|
sc.defaultHandler = Wrap(func(w http.ResponseWriter, c *models.ReqContext) {
|
||||||
|
|
@ -109,7 +110,8 @@ func TestLoginOAuthRedirect(t *testing.T) {
|
||||||
|
|
||||||
sc := setupScenarioContext("/login")
|
sc := setupScenarioContext("/login")
|
||||||
hs := &HTTPServer{
|
hs := &HTTPServer{
|
||||||
Cfg: setting.NewCfg(),
|
Cfg: setting.NewCfg(),
|
||||||
|
License: models.OSSLicensingService{},
|
||||||
}
|
}
|
||||||
|
|
||||||
sc.defaultHandler = Wrap(func(c *models.ReqContext) {
|
sc.defaultHandler = Wrap(func(c *models.ReqContext) {
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,11 @@ import (
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
m "github.com/grafana/grafana/pkg/models"
|
m "github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/teamguardian"
|
"github.com/grafana/grafana/pkg/services/teamguardian"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
|
||||||
"github.com/grafana/grafana/pkg/util"
|
"github.com/grafana/grafana/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GET /api/teams/:teamId/members
|
// GET /api/teams/:teamId/members
|
||||||
func GetTeamMembers(c *m.ReqContext) Response {
|
func (hs *HTTPServer) GetTeamMembers(c *m.ReqContext) Response {
|
||||||
query := m.GetTeamMembersQuery{OrgId: c.OrgId, TeamId: c.ParamsInt64(":teamId")}
|
query := m.GetTeamMembersQuery{OrgId: c.OrgId, TeamId: c.ParamsInt64(":teamId")}
|
||||||
|
|
||||||
if err := bus.Dispatch(&query); err != nil {
|
if err := bus.Dispatch(&query); err != nil {
|
||||||
|
|
@ -21,7 +20,7 @@ func GetTeamMembers(c *m.ReqContext) Response {
|
||||||
member.AvatarUrl = dtos.GetGravatarUrl(member.Email)
|
member.AvatarUrl = dtos.GetGravatarUrl(member.Email)
|
||||||
member.Labels = []string{}
|
member.Labels = []string{}
|
||||||
|
|
||||||
if setting.IsEnterprise && member.External {
|
if hs.License.HasValidLicense() && member.External {
|
||||||
authProvider := GetAuthProviderLabel(member.AuthModule)
|
authProvider := GetAuthProviderLabel(member.AuthModule)
|
||||||
member.Labels = append(member.Labels, authProvider)
|
member.Labels = append(member.Labels, authProvider)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ import (
|
||||||
|
|
||||||
_ "github.com/crewjam/saml"
|
_ "github.com/crewjam/saml"
|
||||||
_ "github.com/gobwas/glob"
|
_ "github.com/gobwas/glob"
|
||||||
|
"github.com/grafana/grafana/pkg/models"
|
||||||
|
"github.com/grafana/grafana/pkg/registry"
|
||||||
_ "github.com/jung-kurt/gofpdf"
|
_ "github.com/jung-kurt/gofpdf"
|
||||||
_ "github.com/robfig/cron"
|
_ "github.com/robfig/cron"
|
||||||
_ "github.com/robfig/cron/v3"
|
_ "github.com/robfig/cron/v3"
|
||||||
|
|
@ -13,4 +15,8 @@ import (
|
||||||
_ "gopkg.in/square/go-jose.v2"
|
_ "gopkg.in/square/go-jose.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registry.RegisterService(&models.OSSLicensingService{})
|
||||||
|
}
|
||||||
|
|
||||||
var IsEnterprise bool = false
|
var IsEnterprise bool = false
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
"github.com/grafana/grafana/pkg/login/social"
|
"github.com/grafana/grafana/pkg/login/social"
|
||||||
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
|
|
@ -23,6 +24,7 @@ type UsageStatsService struct {
|
||||||
Cfg *setting.Cfg `inject:""`
|
Cfg *setting.Cfg `inject:""`
|
||||||
Bus bus.Bus `inject:""`
|
Bus bus.Bus `inject:""`
|
||||||
SQLStore *sqlstore.SqlStore `inject:""`
|
SQLStore *sqlstore.SqlStore `inject:""`
|
||||||
|
License models.Licensing `inject:""`
|
||||||
|
|
||||||
oauthProviders map[string]bool
|
oauthProviders map[string]bool
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ func (uss *UsageStatsService) sendUsageStats(oauthProviders map[string]bool) {
|
||||||
"metrics": metrics,
|
"metrics": metrics,
|
||||||
"os": runtime.GOOS,
|
"os": runtime.GOOS,
|
||||||
"arch": runtime.GOARCH,
|
"arch": runtime.GOARCH,
|
||||||
"edition": getEdition(),
|
"edition": getEdition(uss.License.HasValidLicense()),
|
||||||
"packaging": setting.Packaging,
|
"packaging": setting.Packaging,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -182,8 +182,8 @@ func (uss *UsageStatsService) updateTotalStats() {
|
||||||
metrics.StatsTotalActiveAdmins.Set(float64(statsQuery.Result.ActiveAdmins))
|
metrics.StatsTotalActiveAdmins.Set(float64(statsQuery.Result.ActiveAdmins))
|
||||||
}
|
}
|
||||||
|
|
||||||
func getEdition() string {
|
func getEdition(validLicense bool) string {
|
||||||
if setting.IsEnterprise {
|
if validLicense {
|
||||||
return "enterprise"
|
return "enterprise"
|
||||||
}
|
}
|
||||||
return "oss"
|
return "oss"
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ func TestMetrics(t *testing.T) {
|
||||||
uss := &UsageStatsService{
|
uss := &UsageStatsService{
|
||||||
Bus: bus.New(),
|
Bus: bus.New(),
|
||||||
SQLStore: sqlstore.InitTestDB(t),
|
SQLStore: sqlstore.InitTestDB(t),
|
||||||
|
License: models.OSSLicensingService{},
|
||||||
}
|
}
|
||||||
|
|
||||||
var getSystemStatsQuery *models.GetSystemStatsQuery
|
var getSystemStatsQuery *models.GetSystemStatsQuery
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
package models
|
||||||
|
|
||||||
|
type Licensing interface {
|
||||||
|
// HasValidLicense is true if a valid license exists
|
||||||
|
HasValidLicense() bool
|
||||||
|
|
||||||
|
// HasLicense is true if there is a license provided
|
||||||
|
HasLicense() bool
|
||||||
|
|
||||||
|
// Expiry returns the unix epoch timestamp when the license expires, or 0 if no valid license is provided
|
||||||
|
Expiry() int64
|
||||||
|
}
|
||||||
|
|
||||||
|
type OSSLicensingService struct{}
|
||||||
|
|
||||||
|
func (OSSLicensingService) HasLicense() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (OSSLicensingService) Expiry() int64 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (OSSLicensingService) Init() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (OSSLicensingService) HasValidLicense() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue