CDN: Adds support for serving assets over a CDN (#30691)

* CDN: Initial poc support for serving assets over a CDN

* Minor fix

* added build path and test

* fix lint error

* Added edition to cdn path

* Move master builds to a separate path

* Added error handling for the url parsing, changed setting name, and added docs

* Updated sample.ini

* Some property renames

* updated

* Minor update to html

* index template improvements

* Update docs/sources/administration/configuration.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/administration/configuration.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Added ContentDeliveryPrefix to Licence service

* updated docs

* Updated test mock

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>
This commit is contained in:
Torkel Ödegaard
2021-02-01 10:13:09 +01:00
committed by GitHub
parent a8a3e02699
commit c04bc805b5
12 changed files with 164 additions and 61 deletions
+1
View File
@@ -25,6 +25,7 @@ type IndexViewData struct {
AppleTouchIcon template.URL
AppTitle string
Sentry *setting.Sentry
ContentDeliveryURL string
// Nonce is a cryptographic identifier for use with Content Security Policy.
Nonce string
}
+1
View File
@@ -428,6 +428,7 @@ func (hs *HTTPServer) setIndexViewData(c *models.ReqContext) (*dtos.IndexViewDat
NavTree: navTree,
Sentry: &hs.Cfg.Sentry,
Nonce: c.RequestNonce,
ContentDeliveryURL: hs.Cfg.GetContentDeliveryURL((hs.License.Edition())),
}
if setting.DisableGravatar {
+3
View File
@@ -13,6 +13,9 @@ type Licensing interface {
// Return edition
Edition() string
// Used to build content delivery URL
ContentDeliveryPrefix() string
LicenseURL(user *SignedInUser) string
StateInfo() string
@@ -403,6 +403,10 @@ func (t *testLicensingService) StateInfo() string {
return ""
}
func (t *testLicensingService) ContentDeliveryPrefix() string {
return ""
}
func (t *testLicensingService) LicenseURL(user *models.SignedInUser) string {
return ""
}
+4
View File
@@ -32,6 +32,10 @@ func (*OSSLicensingService) StateInfo() string {
return ""
}
func (*OSSLicensingService) ContentDeliveryPrefix() string {
return "grafana-oss"
}
func (l *OSSLicensingService) LicenseURL(user *models.SignedInUser) string {
if user.IsGrafanaAdmin {
return l.Cfg.AppSubURL + "/admin/upgrading"
+29 -3
View File
@@ -197,6 +197,7 @@ type Cfg struct {
SocketPath string
RouterLogging bool
Domain string
CDNRootURL *url.URL
// build
BuildVersion string
@@ -767,7 +768,7 @@ func (cfg *Cfg) Load(args *CommandLineArgs) error {
provisioning := valueAsString(iniFile.Section("paths"), "provisioning", "")
cfg.ProvisioningPath = makeAbsolute(provisioning, HomePath)
if err := readServerSettings(iniFile, cfg); err != nil {
if err := cfg.readServerSettings(iniFile); err != nil {
return err
}
@@ -1251,7 +1252,7 @@ func readSnapshotsSettings(cfg *Cfg, iniFile *ini.File) error {
return nil
}
func readServerSettings(iniFile *ini.File, cfg *Cfg) error {
func (cfg *Cfg) readServerSettings(iniFile *ini.File) error {
server := iniFile.Section("server")
var err error
AppUrl, AppSubUrl, err = parseAppUrlAndSubUrl(server)
@@ -1263,8 +1264,8 @@ func readServerSettings(iniFile *ini.File, cfg *Cfg) error {
cfg.AppURL = AppUrl
cfg.AppSubURL = AppSubUrl
cfg.ServeFromSubPath = ServeFromSubPath
cfg.Protocol = HTTPScheme
protocolStr := valueAsString(server, "protocol", "http")
if protocolStr == "https" {
@@ -1297,9 +1298,34 @@ func readServerSettings(iniFile *ini.File, cfg *Cfg) error {
return err
}
cdnURL := valueAsString(server, "cdn_url", "")
if cdnURL != "" {
cfg.CDNRootURL, err = url.Parse(cdnURL)
if err != nil {
return err
}
}
return nil
}
// GetContentDeliveryURL returns full content delivery URL with /<edition>/<version> added to URL
func (cfg *Cfg) GetContentDeliveryURL(prefix string) string {
if cfg.CDNRootURL != nil {
url := *cfg.CDNRootURL
preReleaseFolder := ""
if strings.Contains(cfg.BuildVersion, "pre") || strings.Contains(cfg.BuildVersion, "alpha") {
preReleaseFolder = "pre-releases"
}
url.Path = path.Join(url.Path, prefix, preReleaseFolder, cfg.BuildVersion)
return url.String()
}
return ""
}
func (cfg *Cfg) readDataSourcesSettings() {
datasources := cfg.Raw.Section("datasources")
cfg.DataSourceLimit = datasources.Key("datasource_limit").MustInt(5000)
+33
View File
@@ -2,6 +2,7 @@ package setting
import (
"bufio"
"net/url"
"os"
"path"
"path/filepath"
@@ -389,3 +390,35 @@ func TestAuthDurationSettings(t *testing.T) {
require.NoError(t, err)
require.Equal(t, maxLifetimeDurationTest, cfg.LoginMaxLifetime)
}
func TestGetCDNPath(t *testing.T) {
var err error
cfg := NewCfg()
cfg.BuildVersion = "v7.5.0-11124"
cfg.CDNRootURL, err = url.Parse("http://cdn.grafana.com")
require.NoError(t, err)
require.Equal(t, "http://cdn.grafana.com/grafana-oss/v7.5.0-11124", cfg.GetContentDeliveryURL("grafana-oss"))
require.Equal(t, "http://cdn.grafana.com/grafana/v7.5.0-11124", cfg.GetContentDeliveryURL("grafana"))
}
func TestGetCDNPathWithPreReleaseVersionAndSubPath(t *testing.T) {
var err error
cfg := NewCfg()
cfg.BuildVersion = "v7.5.0-11124pre"
cfg.CDNRootURL, err = url.Parse("http://cdn.grafana.com/sub")
require.NoError(t, err)
require.Equal(t, "http://cdn.grafana.com/sub/grafana-oss/pre-releases/v7.5.0-11124pre", cfg.GetContentDeliveryURL("grafana-oss"))
require.Equal(t, "http://cdn.grafana.com/sub/grafana/pre-releases/v7.5.0-11124pre", cfg.GetContentDeliveryURL("grafana"))
}
// Adding a case for this in case we switch to proper semver version strings
func TestGetCDNPathWithAlphaVersion(t *testing.T) {
var err error
cfg := NewCfg()
cfg.BuildVersion = "v7.5.0-alpha.11124"
cfg.CDNRootURL, err = url.Parse("http://cdn.grafana.com")
require.NoError(t, err)
require.Equal(t, "http://cdn.grafana.com/grafana-oss/pre-releases/v7.5.0-alpha.11124", cfg.GetContentDeliveryURL("grafana-oss"))
require.Equal(t, "http://cdn.grafana.com/grafana/pre-releases/v7.5.0-alpha.11124", cfg.GetContentDeliveryURL("grafana"))
}