Ask for the Collector ingest endpoint inside the onboarding wizard - #27252
Ask for the Collector ingest endpoint inside the onboarding wizard#27252kroepke wants to merge 7 commits into
Conversation
Instead of redirecting an unconfigured cluster to the Settings page, the onboarding wizard now asks for the ingest endpoint itself: platform and fleet first, then a slim "Confirm how Collectors reach this cluster" strip, and only after that the install command. Confirming performs the one-time collectors bootstrap; the enrollment token is minted afterwards because it is signed with the key that first save creates. Once the config exists the strip turns into a status line that mirrors the Settings page facts (input running, input not running, no input), and changing the port moves the existing ingest input along. Permissions are checked before the user picks anything: a user who cannot edit the config, or who cannot create the ingest input (the built-in Collectors Manager role lacks the input permissions), sees a notice instead of a wizard that cannot finish. On the server the PUT checks the input permission before persisting so a request can no longer half-succeed. The Deployment, Fleets and Instances pages redirect to the Overview instead of Settings while the cluster is unconfigured.
InputEventListener only relaunched an updated input if it was RUNNING or SETUP (from #3824, so that deliberately stopped inputs stay stopped). A FAILED input fell into the same bucket: it was removed from the registry and never started again, so fixing e.g. a port conflict by editing the input left it TERMINATED until a manual start. A failed input was never stopped on purpose, and an update is typically the fix for whatever made it fail, so treat FAILED like RUNNING here.
… onboarding steps
This reverts commit fe50e73.
linuspahl
left a comment
There was a problem hiding this comment.
I couldn’t find any issues with the behavior, just added a few ideas for improvements.
| import { mockCollectorsMutations } from '../../testing/mockMutations'; | ||
| import { mockCollectorPermissions } from '../../testing/mockPermissions'; | ||
|
|
||
| jest.mock('../../hooks'); |
There was a problem hiding this comment.
Usually we don't mock a complete directly and the specific hooks instead.
There was a problem hiding this comment.
I saw the same pattern in other tests in this PR, for example for
jest.mock('components/collectors/hooks', () => ({
useCollectorsConfig: jest.fn(),
}));
| type: 'org.graylog.collectors.input.CollectorIngestHttpInput', | ||
| content_pack: '', | ||
| static_fields: {}, | ||
| }); |
There was a problem hiding this comment.
We have a similar mock for unconfigured and mockInput in other tests already. let's create a shared fixture for it and only adjust the relevant attributes in this file?
|
|
||
| await waitFor(() => { | ||
| expect(screen.getByText(/waiting for connection/i)).toBeInTheDocument(); | ||
| }); |
There was a problem hiding this comment.
Usually we use await screen.findBy instead of expect(...).toBeInTheDocument(),which is async by default. See graylog2-web-interface/CONTRIBUTING.md.
| jest.mock('../../hooks'); | ||
| jest.mock('hooks/useInputsStates'); | ||
| jest.mock('components/collectors/hooks/useSendCollectorsTelemetry'); | ||
| jest.mock('components/inputs/InputStateBadge', () => () => <span>state badge</span>); |
There was a problem hiding this comment.
Usually we don't mock the badge component and just check if the related text is displayed correctly. We usually only test it's existence when it is accessible.
| Confirm endpoint | ||
| </button> | ||
| </div> | ||
| )); |
There was a problem hiding this comment.
We try to avoid the component mocks, in this case we would mock the config API and make sure it returns the "confirmed" status.
There was a problem hiding this comment.
I saw the same pattern in other tests in this PR. If possible we try to avoid something like
jest.mock('components/collectors/common', () => ({ CollectorsPageNavigation: () => <div>collectors nav</div> }));
If there is a runtime error in CollectorsPageNavigation we would not catch it.
| An administrator must set up the Collector ingest endpoint before Collectors can be enrolled. | ||
| </Alert> | ||
| </BodyContainer> | ||
| ); |
There was a problem hiding this comment.
One small thing that surprised me. I read the "Collectors Manager" role description. Grants full control of collectors and fleets (built-in)" and expected they are able to set up the Collector ingest endpoint.
| <Text>{`Ask an administrator to create a Collector Ingest (HTTP) input on port ${config.http.port}.`}</Text> | ||
| )} | ||
| </Stack> | ||
| </Alert> |
There was a problem hiding this comment.
I was a bit overwhelmed by this alert.
I started reading the headline, saw the "Change" button and assumed I am changing the fact that "No ingest input exists", until I saw the "Create input" below.
What confused me as well, when I click "Change" I see the following section:
When I click "Confirm", I am actually creating an input - I thought I am just changing the address because there was already a path to create the input in the previous alert.
Using more descriptive names for "Change" and "Confirm" would already help, but imo we could just combine both screens in one. For example:
No ingest input exists
Collectors can enroll, but they will not be able to send data until an input is created.
Collectors send their logs to this address. It must be reachable from every Collector host: a load balancer, or this server.
| if (!canCompleteSetup) { | ||
| return ( | ||
| <BodyContainer> | ||
| <Alert bsStyle="info" title="Collectors are not set up yet"> |
There was a problem hiding this comment.
Imo the issue here is not that "Collectors are not set up yet", it's that no Collector ingest endpoint has been configured yet.
There was a problem hiding this comment.
When I read the headline for the first time I thought users with the role "Collectors manager" role no longer have the permission to create collectors.
Motivation
On a cluster without a collectors config, every Collectors page redirected to the Settings page and forced the full settings form on the user before anything else. That was confusing: the user came to enroll a collector, not to configure lifecycle thresholds. Design exploration (clickable prototype) settled on asking for the ingest endpoint inside the onboarding wizard, right before the install command that depends on it.
Approach
FirstOnboarding: platform → fleet →IngestEndpointStrip(only when unconfigured) → install command. The enrollment token is minted after the endpoint is confirmed, because the token is signed with the key that first config save creates. Configured clusters skip the strip.IngestEndpointStrip: slim confirm strip (hostname:port, Confirm). Once the config exists it becomes a status line mirroring the Settings page facts: input running / input exists but not running / no input (with "Create input" when permitted). Changing the port moves the existing ingest input via the inputs API (updateCollectorInputPort).inputs:create), shows a notice instead of a wizard that cannot finish.CollectorsConfigResource#putcallsCollectorIngestInputService#ensureCanCreateInputbefore persisting, so a request withcreate_inputcan no longer save the config and then 403 on the input.useCollectorPermissionsgainscanCreateIngestInput/canEditIngestInput.Server fix bundled here
InputEventListener#inputUpdatedonly relaunched an updated input if it was RUNNING or SETUP (#3824 kept deliberately stopped inputs stopped). A FAILED input fell into the same bucket: editing it (e.g. to fix a port conflict) left it TERMINATED until a manual start. Found while testing the port change in the strip; FAILED now relaunches like RUNNING. Same fix applies to the regular Inputs page.Notes
http_external_uri), unchanged.CollectorsSettingsitself is untouched; its own permission gap is tracked in Collectors Settings shows the initial setup form to users who cannot create the ingest input #27250.Section,Group,Stack,Textfromcomponents/common.Screenshots