Skip to content

Commit

Permalink
feat: pass gcom sso_api_token to repo created from install command (g…
Browse files Browse the repository at this point in the history
…rafana#98973)

* feat: pass gcom sso_api_token to repo created from install command

* fix

* fix: extract gcom section to a func

* Update pkg/cmd/grafana-cli/utils/command_line.go

Co-authored-by: Giuseppe Guerra <[email protected]>

* fix: only set gcom token when the request is to GCOM

---------

Co-authored-by: Giuseppe Guerra <[email protected]>
  • Loading branch information
s4kh and xnyo authored Jan 15, 2025
1 parent 79fc26e commit dfe0712
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 22 deletions.
9 changes: 6 additions & 3 deletions pkg/cmd/grafana-cli/commands/install_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ type pluginInstallOpts struct {
repoURL string
pluginURL string
pluginDir string
gcomToken string
}

func newInstallPluginOpts(c utils.CommandLine) pluginInstallOpts {
Expand All @@ -98,6 +99,7 @@ func newInstallPluginOpts(c utils.CommandLine) pluginInstallOpts {
repoURL: c.PluginRepoURL(),
pluginURL: c.PluginURL(),
pluginDir: c.PluginDirectory(),
gcomToken: c.GcomToken(),
}
}

Expand Down Expand Up @@ -132,9 +134,10 @@ func doInstallPlugin(ctx context.Context, pluginID, version string, o pluginInst
}

repository := repo.NewManager(repo.ManagerCfg{
SkipTLSVerify: o.insecure,
BaseURL: o.repoURL,
Logger: services.Logger,
SkipTLSVerify: o.insecure,
BaseURL: o.repoURL,
Logger: services.Logger,
GrafanaComAPIToken: o.gcomToken,
})

// FIXME: Re-enable grafanaVersion. This check was broken in 10.2 so disabling it for the moment.
Expand Down
6 changes: 5 additions & 1 deletion pkg/cmd/grafana-cli/commands/install_command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ func TestValidatePluginRepoConfig(t *testing.T) {
t.Skip("skipping integration test")
}
grafDir, cfgPath := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
GrafanaComAPIURL: "https://grafana-dev.com",
GrafanaComAPIURL: "https://grafana-dev.com",
GrafanaComSSOAPIToken: "token3",
})

c, err := commandstest.NewCliContext(map[string]string{
Expand All @@ -116,6 +117,9 @@ func TestValidatePluginRepoConfig(t *testing.T) {
require.NoError(t, err)
repoURL := c.PluginRepoURL()
require.Equal(t, "https://grafana-dev.com/plugins", repoURL)

token := c.GcomToken()
require.Equal(t, "token3", token)
})

t.Run("Should use config overrides parameter if it is set alongside config parameter", func(t *testing.T) {
Expand Down
27 changes: 21 additions & 6 deletions pkg/cmd/grafana-cli/utils/command_line.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type CommandLine interface {
PluginDirectory() string
PluginRepoURL() string
PluginURL() string
GcomToken() string
}

type ApiClient interface {
Expand Down Expand Up @@ -75,12 +76,7 @@ func (c *ContextCommandLine) PluginRepoURL() string {

// if --config flag is set, try to get the GrafanaComAPIURL setting
if c.ConfigFile() != "" {
configOptions := strings.Split(c.String("configOverrides"), " ")
cfg, err := setting.NewCfgFromArgs(setting.CommandLineArgs{
Config: c.ConfigFile(),
HomePath: c.HomePath(),
Args: append(configOptions, c.Args().Slice()...),
})
cfg, err := c.Config()

if err != nil {
logger.Debug("Could not parse config file", err)
Expand All @@ -92,6 +88,25 @@ func (c *ContextCommandLine) PluginRepoURL() string {
return c.String("repo")
}

func (c *ContextCommandLine) Config() (*setting.Cfg, error) {
configOptions := strings.Split(c.String("configOverrides"), " ")
return setting.NewCfgFromArgs(setting.CommandLineArgs{
Config: c.ConfigFile(),
HomePath: c.HomePath(),
Args: append(configOptions, c.Args().Slice()...),
})
}

func (c *ContextCommandLine) GcomToken() string {
cfg, err := c.Config()

if err != nil {
logger.Debug("Could not parse config file", err)
return ""
}
return cfg.GrafanaComSSOAPIToken
}

func (c *ContextCommandLine) PluginURL() string {
return c.String("pluginUrl")
}
13 changes: 13 additions & 0 deletions pkg/cmd/grafana-cli/utils/command_line_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions pkg/plugins/repo/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"net/http"
"net/url"
"os"
"strings"
"time"

"github.com/grafana/grafana/pkg/plugins/log"
Expand All @@ -24,16 +25,18 @@ type Client struct {
httpClientNoTimeout http.Client
retryCount int
grafanaComAPIToken string
grafanaComAPIURL string

log log.PrettyLogger
}

func NewClient(skipTLSVerify bool, grafanaComAPIToken string, logger log.PrettyLogger) *Client {
func NewClient(skipTLSVerify bool, grafanaComAPIToken, grafanaComAPIURL string, logger log.PrettyLogger) *Client {
return &Client{
httpClient: MakeHttpClient(skipTLSVerify, 10*time.Second),
httpClientNoTimeout: MakeHttpClient(skipTLSVerify, 0),
log: logger,
grafanaComAPIToken: grafanaComAPIToken,
grafanaComAPIURL: grafanaComAPIURL,
}
}

Expand Down Expand Up @@ -233,7 +236,7 @@ func (c *Client) createReq(ctx context.Context, url *url.URL, compatOpts CompatO
req.Header.Set("grafana-origin", orig.(string))
}

if c.grafanaComAPIToken != "" {
if strings.HasPrefix(url.String(), c.grafanaComAPIURL) && c.grafanaComAPIToken != "" {
req.Header.Set("Authorization", "Bearer "+c.grafanaComAPIToken)
}

Expand Down
26 changes: 23 additions & 3 deletions pkg/plugins/repo/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func Test_Download(t *testing.T) {
require.Equal(t, 2, count, "should retry on error")
})

t.Run("it should use gcom token when it's available", func(t *testing.T) {
t.Run("it should use gcom token when the token is available and request is to GCOM", func(t *testing.T) {
expectedToken := "token-test"
var gcomCalled bool
fakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
Expand All @@ -82,9 +82,29 @@ func Test_Download(t *testing.T) {
}))
defer fakeServer.Close()
cli := fakeServer.Client()
repo := Client{httpClient: *cli, httpClientNoTimeout: *cli, log: log.NewPrettyLogger("test"), grafanaComAPIToken: expectedToken}
_, err := repo.Download(context.Background(), fakeServer.URL, "", CompatOpts{})
pluginURL := fakeServer.URL + "/api/plugins/test-datasource"
gcomAPIURL := fakeServer.URL + "/api/plugins"
repo := Client{httpClient: *cli, httpClientNoTimeout: *cli, log: log.NewPrettyLogger("test"), grafanaComAPIToken: expectedToken, grafanaComAPIURL: gcomAPIURL}
_, err := repo.Download(context.Background(), pluginURL, "", CompatOpts{})
require.NoError(t, err)
require.True(t, gcomCalled)
})

t.Run("it should not set gcom token when the token is available but request is NOT to GCOM", func(t *testing.T) {
expectedToken := "token-test"
var serverCalled bool
fakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
require.Empty(t, token, "token should not be set")
err := writeFakeZip(w)
require.NoError(t, err)
serverCalled = true
}))
defer fakeServer.Close()
cli := fakeServer.Client()
repo := Client{httpClient: *cli, httpClientNoTimeout: *cli, log: log.NewPrettyLogger("test"), grafanaComAPIToken: expectedToken, grafanaComAPIURL: "https://grafana.com/api/plugins"}
_, err := repo.Download(context.Background(), fakeServer.URL, "", CompatOpts{})
require.NoError(t, err)
require.True(t, serverCalled)
})
}
12 changes: 5 additions & 7 deletions pkg/plugins/repo/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ import (
)

type Manager struct {
client *Client
baseURL string
client *Client

log log.PrettyLogger
}
Expand Down Expand Up @@ -43,9 +42,8 @@ type ManagerCfg struct {

func NewManager(cfg ManagerCfg) *Manager {
return &Manager{
baseURL: cfg.BaseURL,
client: NewClient(cfg.SkipTLSVerify, cfg.GrafanaComAPIToken, cfg.Logger),
log: cfg.Logger,
client: NewClient(cfg.SkipTLSVerify, cfg.GrafanaComAPIToken, cfg.BaseURL, cfg.Logger),
log: cfg.Logger,
}
}

Expand Down Expand Up @@ -101,12 +99,12 @@ func (m *Manager) PluginVersion(ctx context.Context, pluginID, version string, c
}

func (m *Manager) downloadURL(pluginID, version string) string {
return fmt.Sprintf("%s/%s/versions/%s/download", m.baseURL, pluginID, version)
return fmt.Sprintf("%s/%s/versions/%s/download", m.client.grafanaComAPIURL, pluginID, version)
}

// grafanaCompatiblePluginVersions will get version info from /api/plugins/$pluginID/versions
func (m *Manager) grafanaCompatiblePluginVersions(ctx context.Context, pluginID string, compatOpts CompatOpts) ([]Version, error) {
u, err := url.Parse(m.baseURL)
u, err := url.Parse(m.client.grafanaComAPIURL)
if err != nil {
return nil, err
}
Expand Down
10 changes: 10 additions & 0 deletions pkg/tests/testinfra/testinfra.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ func StartGrafanaEnv(t *testing.T, grafDir, cfgPath string) (string, *server.Tes

// CreateGrafDir creates the Grafana directory.
// The log by default is muted in the regression test, to activate it, pass option EnableLog = true
//
//nolint:gocyclo
func CreateGrafDir(t *testing.T, opts GrafanaOpts) (string, string) {
t.Helper()

Expand Down Expand Up @@ -459,6 +461,13 @@ func CreateGrafDir(t *testing.T, opts GrafanaOpts) (string, string) {
_, err = grafanaComSection.NewKey("api_url", opts.GrafanaComAPIURL)
require.NoError(t, err)
}
if opts.GrafanaComSSOAPIToken != "" {
grafanaComSection, err := getOrCreateSection("grafana_com")
require.NoError(t, err)
_, err = grafanaComSection.NewKey("sso_api_token", opts.GrafanaComSSOAPIToken)
require.NoError(t, err)
}

if opts.UnifiedStorageConfig != nil {
for k, v := range opts.UnifiedStorageConfig {
section, err := getOrCreateSection(fmt.Sprintf("unified_storage.%s", k))
Expand Down Expand Up @@ -519,6 +528,7 @@ type GrafanaOpts struct {
QueryRetries int64
GrafanaComAPIURL string
UnifiedStorageConfig map[string]setting.UnifiedStorageConfig
GrafanaComSSOAPIToken string

// When "unified-grpc" is selected it will also start the grpc server
APIServerStorageType options.StorageType
Expand Down

0 comments on commit dfe0712

Please sign in to comment.