CloudMigrations: Remove onPremToCloudMigrationsAuthApiMig feature flag (#99368)

pull/99011/head^2
lean.dev 4 months ago committed by GitHub
parent 63a89afe00
commit b3209b1e01
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md
  2. 1
      packages/grafana-data/src/types/featureToggles.gen.ts
  3. 16
      pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration.go
  4. 6
      pkg/services/featuremgmt/registry.go
  5. 1
      pkg/services/featuremgmt/toggles_gen.csv
  6. 4
      pkg/services/featuremgmt/toggles_gen.go
  7. 3
      pkg/services/featuremgmt/toggles_gen.json
  8. 289
      pkg/services/gcom/gcomauth.go

@ -191,7 +191,6 @@ Experimental features might be changed or removed without prior notice.
| `tableSharedCrosshair` | Enables shared crosshair in table panel |
| `kubernetesFeatureToggles` | Use the kubernetes API for feature toggle management in the frontend |
| `newFolderPicker` | Enables the nested folder picker without having nested folders enabled |
| `onPremToCloudMigrationsAuthApiMig` | Enables the use of auth api instead of gcom for internal token services. Requires `onPremToCloudMigrations` to be enabled in conjunction. |
| `scopeApi` | In-development feature flag for the scope api using the app platform. |
| `sqlExpressions` | Enables using SQL and DuckDB functions as Expressions. |
| `nodeGraphDotLayout` | Changed the layout algorithm for the node graph |

@ -153,7 +153,6 @@ export interface FeatureToggles {
newFolderPicker?: boolean;
jitterAlertRulesWithinGroups?: boolean;
onPremToCloudMigrations?: boolean;
onPremToCloudMigrationsAuthApiMig?: boolean;
alertingSaveStatePeriodic?: boolean;
scopeApi?: boolean;
promQLScope?: boolean;

@ -168,18 +168,12 @@ func ProvideService(
}
s.gcomService = gcom.New(gcom.Config{ApiURL: cfg.GrafanaComAPIURL, Token: cfg.CloudMigration.GcomAPIToken}, httpClientGcom)
if features.IsEnabledGlobally(featuremgmt.FlagOnPremToCloudMigrationsAuthApiMig) {
s.log.Info("using authapi client because feature flag is enabled")
httpClientAuthApi, err := httpClientProvider.New()
if err != nil {
return nil, fmt.Errorf("creating http client for AuthApi: %w", err)
}
// the api token is the same as for gcom
s.authApiService = authapi.New(authapi.Config{ApiURL: cfg.CloudMigration.AuthAPIUrl, Token: cfg.CloudMigration.GcomAPIToken}, httpClientAuthApi)
} else {
s.log.Info("using gcom client for auth")
s.authApiService = gcom.New(gcom.Config{ApiURL: cfg.GrafanaComAPIURL, Token: cfg.CloudMigration.GcomAPIToken}, httpClientGcom).(*gcom.GcomClient)
httpClientAuthApi, err := httpClientProvider.New()
if err != nil {
return nil, fmt.Errorf("creating http client for AuthApi: %w", err)
}
// the api token is the same as for gcom
s.authApiService = authapi.New(authapi.Config{ApiURL: cfg.CloudMigration.AuthAPIUrl, Token: cfg.CloudMigration.GcomAPIToken}, httpClientAuthApi)
} else {
s.gmsClient = gmsclient.NewInMemoryClient()
s.gcomService = &gcomStub{}

@ -1020,12 +1020,6 @@ var (
Owner: grafanaOperatorExperienceSquad,
Expression: "true",
},
{
Name: "onPremToCloudMigrationsAuthApiMig",
Description: "Enables the use of auth api instead of gcom for internal token services. Requires `onPremToCloudMigrations` to be enabled in conjunction.",
Stage: FeatureStageExperimental,
Owner: grafanaOperatorExperienceSquad,
},
{
Name: "alertingSaveStatePeriodic",
Description: "Writes the state periodically to the database, asynchronous to rule evaluation",

@ -134,7 +134,6 @@ alertingQueryOptimization,GA,@grafana/alerting-squad,false,false,false
newFolderPicker,experimental,@grafana/grafana-frontend-platform,false,false,true
jitterAlertRulesWithinGroups,preview,@grafana/alerting-squad,false,true,false
onPremToCloudMigrations,preview,@grafana/grafana-operator-experience-squad,false,false,false
onPremToCloudMigrationsAuthApiMig,experimental,@grafana/grafana-operator-experience-squad,false,false,false
alertingSaveStatePeriodic,privatePreview,@grafana/alerting-squad,false,false,false
scopeApi,experimental,@grafana/grafana-app-platform-squad,false,false,false
promQLScope,GA,@grafana/oss-big-tent,false,false,false

1 Name Stage Owner requiresDevMode RequiresRestart FrontendOnly
134 newFolderPicker experimental @grafana/grafana-frontend-platform false false true
135 jitterAlertRulesWithinGroups preview @grafana/alerting-squad false true false
136 onPremToCloudMigrations preview @grafana/grafana-operator-experience-squad false false false
onPremToCloudMigrationsAuthApiMig experimental @grafana/grafana-operator-experience-squad false false false
137 alertingSaveStatePeriodic privatePreview @grafana/alerting-squad false false false
138 scopeApi experimental @grafana/grafana-app-platform-squad false false false
139 promQLScope GA @grafana/oss-big-tent false false false

@ -547,10 +547,6 @@ const (
// Enable the Grafana Migration Assistant, which helps you easily migrate on-prem resources, such as dashboards, folders, and data source configurations, to your Grafana Cloud stack.
FlagOnPremToCloudMigrations = "onPremToCloudMigrations"
// FlagOnPremToCloudMigrationsAuthApiMig
// Enables the use of auth api instead of gcom for internal token services. Requires `onPremToCloudMigrations` to be enabled in conjunction.
FlagOnPremToCloudMigrationsAuthApiMig = "onPremToCloudMigrationsAuthApiMig"
// FlagAlertingSaveStatePeriodic
// Writes the state periodically to the database, asynchronous to rule evaluation
FlagAlertingSaveStatePeriodic = "alertingSaveStatePeriodic"

@ -2721,7 +2721,8 @@
"metadata": {
"name": "onPremToCloudMigrationsAuthApiMig",
"resourceVersion": "1732033809064",
"creationTimestamp": "2024-11-21T18:46:06Z"
"creationTimestamp": "2024-11-21T18:46:06Z",
"deletionTimestamp": "2025-01-22T11:00:18Z"
},
"spec": {
"description": "Enables the use of auth api instead of gcom for internal token services. Requires `onPremToCloudMigrations` to be enabled in conjunction.",

@ -1,289 +0,0 @@
package gcom
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"github.com/grafana/grafana/pkg/services/authapi"
)
// this will be removed when service in authapi is fully enabled
type listTokensResponse struct {
Items []authapi.TokenView `json:"items"`
}
type listAccessPoliciesResponse struct {
Items []authapi.AccessPolicy `json:"items"`
}
var _ authapi.Service = (*GcomClient)(nil)
func (client *GcomClient) CreateAccessPolicy(ctx context.Context, params authapi.CreateAccessPolicyParams, payload authapi.CreateAccessPolicyPayload) (authapi.AccessPolicy, error) {
endpoint, err := url.JoinPath(client.cfg.ApiURL, "/v1/accesspolicies")
if err != nil {
return authapi.AccessPolicy{}, fmt.Errorf("building gcom access policy url: %w", err)
}
body, err := json.Marshal(&payload)
if err != nil {
return authapi.AccessPolicy{}, fmt.Errorf("marshaling request body: %w", err)
}
request, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, bytes.NewReader(body))
if err != nil {
return authapi.AccessPolicy{}, fmt.Errorf("creating http request: %w", err)
}
query := url.Values{}
query.Set("region", params.Region)
request.URL.RawQuery = query.Encode()
request.Header.Set("x-request-id", params.RequestID)
request.Header.Set("Content-Type", "application/json")
request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", client.cfg.Token))
response, err := client.httpClient.Do(request)
if err != nil {
return authapi.AccessPolicy{}, fmt.Errorf("sending http request to create access policy: %w", err)
}
defer func() {
if err := response.Body.Close(); err != nil {
client.log.Error("closing http response body", "err", err.Error())
}
}()
if response.StatusCode != http.StatusOK {
body, _ := io.ReadAll(response.Body)
return authapi.AccessPolicy{}, fmt.Errorf("unexpected response when creating access policy: code=%d body=%s", response.StatusCode, body)
}
var accessPolicy authapi.AccessPolicy
if err := json.NewDecoder(response.Body).Decode(&accessPolicy); err != nil {
return accessPolicy, fmt.Errorf("unmarshaling response body: %w", err)
}
return accessPolicy, nil
}
func (client *GcomClient) DeleteAccessPolicy(ctx context.Context, params authapi.DeleteAccessPolicyParams) (bool, error) {
endpoint, err := url.JoinPath(client.cfg.ApiURL, "/v1/accesspolicies/", params.AccessPolicyID)
if err != nil {
return false, fmt.Errorf("building gcom access policy url: %w", err)
}
request, err := http.NewRequestWithContext(ctx, http.MethodDelete, endpoint, nil)
if err != nil {
return false, fmt.Errorf("creating http request: %w", err)
}
query := url.Values{}
query.Set("region", params.Region)
request.URL.RawQuery = query.Encode()
request.Header.Set("x-request-id", params.RequestID)
request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", client.cfg.Token))
response, err := client.httpClient.Do(request)
if err != nil {
return false, fmt.Errorf("sending http request to create access policy: %w", err)
}
defer func() {
if err := response.Body.Close(); err != nil {
client.log.Error("closing http response body", "err", err.Error())
}
}()
if response.StatusCode == http.StatusNotFound {
return false, nil
}
if response.StatusCode == http.StatusOK || response.StatusCode == http.StatusNoContent {
return true, nil
}
body, _ := io.ReadAll(response.Body)
return false, fmt.Errorf("unexpected response when deleting access policy: code=%d body=%s", response.StatusCode, body)
}
func (client *GcomClient) ListAccessPolicies(ctx context.Context, params authapi.ListAccessPoliciesParams) ([]authapi.AccessPolicy, error) {
endpoint, err := url.JoinPath(client.cfg.ApiURL, "/v1/accesspolicies")
if err != nil {
return nil, fmt.Errorf("building gcom access policy url: %w", err)
}
request, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil)
if err != nil {
return nil, fmt.Errorf("creating http request: %w", err)
}
query := url.Values{}
query.Set("region", params.Region)
query.Set("name", params.Name)
request.URL.RawQuery = query.Encode()
request.Header.Set("x-request-id", params.RequestID)
request.Header.Set("Accept", "application/json")
request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", client.cfg.Token))
response, err := client.httpClient.Do(request)
if err != nil {
return nil, fmt.Errorf("sending http request to create access policy: %w", err)
}
defer func() {
if err := response.Body.Close(); err != nil {
client.log.Error("closing http response body", "err", err.Error())
}
}()
if response.StatusCode != http.StatusOK {
body, _ := io.ReadAll(response.Body)
return nil, fmt.Errorf("unexpected response when listing access policies: code=%d body=%s", response.StatusCode, body)
}
var responseBody listAccessPoliciesResponse
if err := json.NewDecoder(response.Body).Decode(&responseBody); err != nil {
return responseBody.Items, fmt.Errorf("unmarshaling response body: %w", err)
}
return responseBody.Items, nil
}
func (client *GcomClient) ListTokens(ctx context.Context, params authapi.ListTokenParams) ([]authapi.TokenView, error) {
endpoint, err := url.JoinPath(client.cfg.ApiURL, "/v1/tokens")
if err != nil {
return nil, fmt.Errorf("building gcom tokens url: %w", err)
}
request, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil)
if err != nil {
return nil, fmt.Errorf("creating http request: %w", err)
}
query := url.Values{}
query.Set("region", params.Region)
query.Set("accessPolicyName", params.AccessPolicyName)
query.Set("name", params.TokenName)
request.URL.RawQuery = query.Encode()
request.Header.Set("x-request-id", params.RequestID)
request.Header.Set("Content-Type", "application/json")
request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", client.cfg.Token))
response, err := client.httpClient.Do(request)
if err != nil {
return nil, fmt.Errorf("sending http request to list access tokens: %w", err)
}
defer func() {
if err := response.Body.Close(); err != nil {
client.log.Error("closing http response body", "err", err.Error())
}
}()
if response.StatusCode != http.StatusOK {
body, _ := io.ReadAll(response.Body)
return nil, fmt.Errorf("unexpected response when fetching access tokens: code=%d body=%s", response.StatusCode, body)
}
var body listTokensResponse
if err := json.NewDecoder(response.Body).Decode(&body); err != nil {
return nil, fmt.Errorf("unmarshaling response body: %w", err)
}
return body.Items, nil
}
func (client *GcomClient) CreateToken(ctx context.Context, params authapi.CreateTokenParams, payload authapi.CreateTokenPayload) (authapi.Token, error) {
endpoint, err := url.JoinPath(client.cfg.ApiURL, "/v1/tokens")
if err != nil {
return authapi.Token{}, fmt.Errorf("building gcom tokens url: %w", err)
}
body, err := json.Marshal(&payload)
if err != nil {
return authapi.Token{}, fmt.Errorf("marshaling request body: %w", err)
}
request, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, bytes.NewReader(body))
if err != nil {
return authapi.Token{}, fmt.Errorf("creating http request: %w", err)
}
query := url.Values{}
query.Set("region", params.Region)
request.URL.RawQuery = query.Encode()
request.Header.Set("x-request-id", params.RequestID)
request.Header.Set("Content-Type", "application/json")
request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", client.cfg.Token))
response, err := client.httpClient.Do(request)
if err != nil {
return authapi.Token{}, fmt.Errorf("sending http request to create access token: %w", err)
}
defer func() {
if err := response.Body.Close(); err != nil {
client.log.Error("closing http response body", "err", err.Error())
}
}()
if response.StatusCode != http.StatusOK {
body, _ := io.ReadAll(response.Body)
return authapi.Token{}, fmt.Errorf("unexpected response when creating access token: code=%d body=%s", response.StatusCode, body)
}
var token authapi.Token
if err := json.NewDecoder(response.Body).Decode(&token); err != nil {
return token, fmt.Errorf("unmarshaling response body: %w", err)
}
return token, nil
}
func (client *GcomClient) DeleteToken(ctx context.Context, params authapi.DeleteTokenParams) error {
endpoint, err := url.JoinPath(client.cfg.ApiURL, "/v1/tokens", params.TokenID)
if err != nil {
return fmt.Errorf("building gcom tokens url: %w", err)
}
request, err := http.NewRequestWithContext(ctx, http.MethodDelete, endpoint, nil)
if err != nil {
return fmt.Errorf("creating http request: %w", err)
}
query := url.Values{}
query.Set("region", params.Region)
request.URL.RawQuery = query.Encode()
request.Header.Set("x-request-id", params.RequestID)
request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", client.cfg.Token))
response, err := client.httpClient.Do(request)
if err != nil {
return fmt.Errorf("sending http request to delete access token: %w", err)
}
defer func() {
if err := response.Body.Close(); err != nil {
client.log.Error("closing http response body", "err", err.Error())
}
}()
if response.StatusCode == http.StatusNotFound {
return fmt.Errorf("token id: %s %w", params.TokenID, ErrTokenNotFound)
}
if response.StatusCode != http.StatusOK && response.StatusCode != http.StatusNoContent {
body, _ := io.ReadAll(response.Body)
return fmt.Errorf("unexpected response when deleting access token: code=%d body=%s", response.StatusCode, body)
}
return nil
}
Loading…
Cancel
Save