Skip to content

Conversation

@dgzlopes
Copy link
Contributor

@dgzlopes dgzlopes commented Nov 17, 2025

What?

As described in the Design Doc, this PR implements support to configure the default Grafana Cloud Stack.

Checklist

  • I have performed a self-review of my code.
  • I have commented on my code, particularly in hard-to-understand areas.
  • I have added tests for my changes.
  • I have run linter and tests locally (make check) and all pass.

Checklist: Documentation (only for k6 maintainers and if relevant)

Please do not merge this PR until the following items are filled out.

  • I have added the correct milestone and labels to the PR.
  • I have updated the release notes: link
  • I have updated or added an issue to the k6-documentation: grafana/k6-docs#NUMBER if applicable
  • I have updated or added an issue to the TypeScript definitions: grafana/k6-DefinitelyTyped#NUMBER if applicable

Related PR(s)/Issue(s)

Closes #4008

@dgzlopes dgzlopes temporarily deployed to azure-trusted-signing November 17, 2025 10:45 — with GitHub Actions Inactive
@dgzlopes dgzlopes temporarily deployed to azure-trusted-signing November 17, 2025 10:48 — with GitHub Actions Inactive
@dgzlopes dgzlopes temporarily deployed to azure-trusted-signing November 17, 2025 11:23 — with GitHub Actions Inactive
@dgzlopes dgzlopes temporarily deployed to azure-trusted-signing November 17, 2025 11:24 — with GitHub Actions Inactive
@dgzlopes dgzlopes temporarily deployed to azure-trusted-signing November 17, 2025 11:36 — with GitHub Actions Inactive
@dgzlopes dgzlopes temporarily deployed to azure-trusted-signing November 17, 2025 11:38 — with GitHub Actions Inactive
@dgzlopes dgzlopes marked this pull request as ready for review November 17, 2025 11:52
@dgzlopes dgzlopes requested a review from a team as a code owner November 17, 2025 11:52
cloudapi/api.go Outdated
// ValidateAuth validates a token and stack URL, returning the stack ID and default project ID.
// The stackURL must be a normalized full URL (e.g., https://my-team.grafana.net).
func (c *Client) ValidateAuth(stackURL string) (*AuthenticationResponse, error) {
req, err := http.NewRequest(http.MethodGet, "https://api.k6.io/cloud/v6/auth", nil) //nolint:noctx
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not blocking nor critical 👇🏻

I understand why this cannot use c.baseURL here, as the baseURL contains the v1 path. However, I would prefer for us not to hardcode the API URL here if possible.

I would suggest refactoring the client if possible to store the API version it talks to, and select the base api path to use according:

  • "/v1" if talking to the v1 API
  • "/cloud/v6" if talking to the v6 API

Specifically thinking of this code here:

baseURL: fmt.Sprintf("%s/v1", host),

In an ideal world, I think this should call something along the lines of c.BaseURL(cloudAPIVersion6) and get a fully qualified url as a result 🙇🏻

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made the changes! Let me know what you think 👀

Comment on lines +262 to +267
return fmt.Errorf(
"your stack is invalid - please, consult the Grafana Cloud k6 documentation "+
"for instructions on how to get yours: "+
"https://grafana.com/docs/grafana-cloud/testing/k6/author-run/something-stack: %w",
err)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This URL doesn't resolve in my browser, I would suggest pointing to a URL that does exist and help the user? 🙇🏻

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sadly, I think there is no page for this at the moment. The closest is this but it doesn't really tell you anything...

Thoughts on this @heitortsergent?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the information we need from the docs about how to retrieve the stack name or URL?

Copy link
Contributor

@codebien codebien left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @dgzlopes, thanks for your contribution. 🙇

It sounds a great start, however the main missing point is the complete absence of test coverage. This is a mission critical feature, so I don't think we should release this without a good coverage.
Most of the building blocks should be already there for making this possible.

In addition, if possible, anything not strictly necessary for the stack/project ID definition should be moved out in a separated pull request to reduce the current complexity.

cloudapi/api.go Outdated
// ValidateAuth validates a token and stack URL, returning the stack ID and default project ID.
// The stackURL must be a normalized full URL (e.g., https://my-team.grafana.net).
func (c *Client) ValidateAuth(stackURL string) (*AuthenticationResponse, error) {
req, err := http.NewRequest(http.MethodGet, "https://api.k6.io/cloud/v6/auth", nil) //nolint:noctx
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
req, err := http.NewRequest(http.MethodGet, "https://api.k6.io/cloud/v6/auth", nil) //nolint:noctx
req, err := http.NewRequestWithContext(http.MethodGet, c.authBase, nil) //nolint:noctx

In addition, we should use the context, so we can cancel the requests when the user aborts the script.

}

// AuthenticationResponse represents the response from the /cloud/v6/auth endpoint.
type AuthenticationResponse struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
type AuthenticationResponse struct {
type authenticationResponse struct {

do we really need to export it?

err := migrateLegacyConfigFileIfAny(c.globalState)
if err != nil {
return err
if !checkIfMigrationCompleted(c.globalState) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you isolate this change in a separated pull request, please? It doesn't sound necessary to stay here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change should stay in a cloud file and not in common.go

return cloudConfig.DefaultProjectID.Int64, nil
}
return 0, fmt.Errorf(
"default stack configured but default project ID not available - " +
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"default stack configured but default project ID not available - " +
"default stack configured but the default project ID is not available - " +

ProjectID null.Int `json:"projectID" envconfig:"K6_CLOUD_PROJECT_ID"`
Name null.String `json:"name" envconfig:"K6_CLOUD_NAME"`
StackID null.Int `json:"stackID,omitempty" envconfig:"K6_CLOUD_STACK_ID"`
StackURL null.String `json:"stackURL,omitempty" envconfig:"K6_CLOUD_STACK"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
StackURL null.String `json:"stackURL,omitempty" envconfig:"K6_CLOUD_STACK"`
StackURL null.String `json:"stackURL,omitempty" envconfig:"K6_CLOUD_STACK_URL"`

I added URL because 2 out of 3 have it, but if the intention is to not have it then remove it from the other two.

Comment on lines +255 to +257

// Only merge ProjectID, Name, Token, and StackID from options.
// StackURL and DefaultProjectID can only be set via login.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we get this check in a position near to the others, please?

Comment on lines +28 to +32
consolidatedCurrentConfig, warn, err := cloudapi.GetConsolidatedConfig(
jsonRawConf, gs.Env, "", nil, nil)
if err != nil {
return "", 0, 0, err
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expect the config to be a dependency and not a direct call here.

// as expected by the Cloud output.
//
//nolint:funlen
//nolint:funlen,gocognit,cyclop
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a signal that we should try to do better here. I'd like to see a proposal for an improvement.

c.gs.Events.UnsubscribeAll()
}()

printBanner(c.gs)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we expect this

@dgzlopes dgzlopes temporarily deployed to azure-trusted-signing November 18, 2025 09:18 — with GitHub Actions Inactive
@dgzlopes dgzlopes temporarily deployed to azure-trusted-signing November 18, 2025 09:20 — with GitHub Actions Inactive
@oleiade oleiade requested review from fornfrey and yorugac November 18, 2025 11:32
@oleiade
Copy link
Contributor

oleiade commented Nov 18, 2025

I added you as reviewers @yorugac @fornfrey as this impacts the transition to v6 API down the road. If you find the time to take a look, and help us make sure we do the right thing, that would be very much appreciated 🙇🏻

@oleiade
Copy link
Contributor

oleiade commented Nov 18, 2025

Also 🏓 👀 @AgnesToulet as this will be relevant to using the v6 api in k6, as it implements a requirement to be able to even interact with the api (the stack url/id we mentioned prior).


// ValidateAuth validates a token and stack URL, returning the stack ID and default project ID.
// The stackURL must be a normalized full URL (e.g., https://my-team.grafana.net).
func (c *Client) ValidateAuth(stackURL string) (*AuthenticationResponse, error) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have the same question actually. And more than that, should it be the goal for all v6 endpoints to be called via that library?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be great but would probably need a larger refactor, not directly related to what this PR does. I'm planning to use this library when working on #5009 and I can update this function then.

}
}()

if err := CheckResponse(resp); err != nil {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error schema in v6 AP is different from the old one. Should the error handling code be updated too?

Comment on lines +70 to +80
// BaseURL returns the fully qualified base URL for the specified API version.
// It returns:
// - "{client.host}/v1" for APIVersion1
// - "https://api.k6.io/cloud/v6" for APIVersion6
func (c *Client) BaseURL(apiVersion APIVersion) string {
switch apiVersion {
case APIVersion6:
return "https://api.k6.io/cloud/v6"
default:
return fmt.Sprintf("%s/v1", c.host)
}
Copy link
Contributor

@yorugac yorugac Nov 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change might break k6-operator code if PLZ endpoints (a mix of v1 and v4 at api.k6.io) are not taken into account here. They don't seem to be ATM.

@yorugac
Copy link
Contributor

yorugac commented Nov 18, 2025

Thanks for the ping @oleiade.

I have left a couple of comments already but there is more 😂 Here are my questions / observations about this change (this is not a review as such, but more of my thinking about "how we're going to use this in the future"):

  1. ATM we have K6_CLOUD_HOST env var which allows us to do rather versatile internal testing. How does this change together with the move to API v6 impact those workflows?

  2. A note on consistency of UX. The warnings around "falling back to default project / stack" are currently strongly tied to k6 CLI, AFAIS. It means that k6-operator is very unlikely to have the same UX around fallback to defaults. It might be possible to implement some similar warnings there but definitely not for all cases.

  3. Since user can set stack and project ID directly in the script, what would happen if they are both set and don't match each other? This should raise an error and prevent creation of the test, I assume, but at what level exactly would it happen? Understanding this would help ensure that it's propagated correctly. (including k6-operator use cases)

  4. I don't see addition of CLI arguments for k6 cloud run command here: is it planned as the next iteration? Or config file and script's options will be the only way to set the stack?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add option to specify the stack id when using the k6 cloud login command

7 participants