ui: Gracefully recover from non-existent DC errors (#11077)

* ui: Gracefully recover from non-existent DC errors

This PR fixes what happens in the UI if you try to navigate to a non-existing DC.

When we received a 500 error from an API response due to a non-existent DC, previously we would show a 404 error, which is what we were trying to convey. But in the spirit of the UI being a 'thin client', its probably best to just show the 500 error from the API response, which may help folks to debug any issues better.

* Automatically set the CONSUL_DATACENTER_LOCAL env var for testing
This commit is contained in:
John Cowen 2021-09-22 18:26:36 +01:00 committed by GitHub
parent f8afe3e9db
commit 5da06645b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 63 additions and 20 deletions

3
.changelog/11077.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:bug
ui: Gracefully recover from non-existant DC errors
```

View File

@ -0,0 +1,11 @@
import Helper from '@ember/component/helper';
import { getOwner } from '@ember/application';
export default class CachedHelper extends Helper {
compute([model], hash) {
return () => {
const container = getOwner(this);
return container.lookup(`service:repository/${model}`).cached(hash);
};
}
}

View File

@ -99,6 +99,13 @@ export default class RepositoryService extends Service {
return this.store.peekRecord(this.getModelName(), id); return this.store.peekRecord(this.getModelName(), id);
} }
cached(params) {
const entries = Object.entries(params);
return this.store.peekAll(this.getModelName()).filter(item => {
return entries.every(([key, value]) => item[key] === value);
});
}
// @deprecated // @deprecated
findAllByDatacenter(params, configuration = {}) { findAllByDatacenter(params, configuration = {}) {
return this.findAll(...arguments); return this.findAll(...arguments);

View File

@ -58,24 +58,44 @@ as |source|>
{{! Make sure we guess and default to the right params when not found }} {{! Make sure we guess and default to the right params when not found }}
{{#let {{#let
(or notfound.dc route.params.dc (env "CONSUL_DATACENTER_LOCAL"))
(if (can "use partitions") (or route.params.partition notfound.partition token.Partition 'default') 'default') (if (can "use partitions") (or route.params.partition notfound.partition token.Partition 'default') 'default')
(if (can "use nspaces") (or route.params.nspace notfound.nspace token.Namespace 'default') 'default') (if (can "use nspaces") (or route.params.nspace notfound.nspace token.Namespace 'default') 'default')
as |dc partition nspace|}} as |partition nspace|}}
{{! Make sure we have enough to show the app chrome}} {{! Make sure we have enough to show the app chrome}}
{{!FIXME}} {{! Don't show anything until we have a list of DCs }}
{{#if (gt dc.length 0)}} <DataSource
{{! Don't show anything until we have a list of DCs }}
<DataSource
@src={{uri '/*/*/*/datacenters'}} @src={{uri '/*/*/*/datacenters'}}
as |dcs|> as |dcs|>
{{! Once we have a list of DCs make sure the DC we are asking for exists }}
{{! If not use the DC that the UI is running in }}
{{#let {{#let
(or
(get (object-at 0 (cached-model
'dc'
(hash
Name=notfound.dc
)
)) 'Name')
(get (object-at 0 (cached-model
'dc'
(hash
Name=route.params.dc
)
)) 'Name')
(env "CONSUL_DATACENTER_LOCAL")
)
dcs.data dcs.data
as |dcs|}}
{{#if (and dcs nspace partition)}} as |dc dcs|}}
{{#if (and (gt dc.length 0) dcs nspace partition)}}
{{! figure out our current DC and convert it to a model }} {{! figure out our current DC and convert it to a model }}
<DataSource <DataSource
@ -133,8 +153,7 @@ as |dcs|}}
</DataSource> </DataSource>
{{/if}} {{/if}}
{{/let}} {{/let}}
</DataSource> </DataSource>
{{/if}}
{{/let}} {{/let}}
{{/if}} {{/if}}
</Route> </Route>

View File

@ -2,7 +2,7 @@
${ ${
range(env('CONSUL_DATACENTER_COUNT', 10)).map((item, i) => { range(env('CONSUL_DATACENTER_COUNT', 10)).map((item, i) => {
if(i === 0) { if(i === 0) {
return `"dc1"`; return `"${env('CONSUL_DATACENTER_LOCAL', 'dc1')}"`;
} }
return ` return `
"${fake.address.countryCode().toLowerCase()}_${ i % 2 ? "west" : "east"}-${i}" "${fake.address.countryCode().toLowerCase()}_${ i % 2 ? "west" : "east"}-${i}"

View File

@ -23,8 +23,6 @@ Feature: dc / error: Recovering from a dc 500 error
Then the url should be /dc-500/services Then the url should be /dc-500/services
And the title should be "Consul" And the title should be "Consul"
Then I see status on the error like "500" Then I see status on the error like "500"
# FIXME
@ignore
Scenario: Clicking the back to root button Scenario: Clicking the back to root button
Given the url "/v1/internal/ui/services" responds with a 200 status Given the url "/v1/internal/ui/services" responds with a 200 status
When I click home When I click home

View File

@ -1,6 +1,4 @@
@setupApplicationTest @setupApplicationTest
# FIXME
@ignore
Feature: dc / services / error Feature: dc / services / error
Scenario: Arriving at the service page that doesn't exist Scenario: Arriving at the service page that doesn't exist
Given 2 datacenter models from yaml Given 2 datacenter models from yaml
@ -8,11 +6,12 @@ Feature: dc / services / error
- dc-1 - dc-1
- dc-2 - dc-2
--- ---
Given the url "/v1/internal/ui/services" responds with a 500 status
When I visit the services page for yaml When I visit the services page for yaml
--- ---
dc: 404-datacenter dc: non-existent-datacenter
--- ---
Then I see status on the error like "404" Then I see status on the error like "500"
@notNamespaceable @notNamespaceable
Scenario: Arriving at the service page Scenario: Arriving at the service page
Given 2 datacenter models from yaml Given 2 datacenter models from yaml

View File

@ -7,11 +7,17 @@ export default function(scenario, create, set, win = window, doc = document) {
return create(number, model); return create(number, model);
}) })
.given(['$number $model model[s]? with the value "$value"'], function(number, model, value) { .given(['$number $model model[s]? with the value "$value"'], function(number, model, value) {
if (model === 'dc') {
doc.cookie = `CONSUL_DATACENTER_LOCAL=${value}`;
}
return create(number, model, value); return create(number, model, value);
}) })
.given( .given(
['$number $model model[s]? from yaml\n$yaml', '$number $model model[s]? from json\n$json'], ['$number $model model[s]? from yaml\n$yaml', '$number $model model[s]? from json\n$json'],
function(number, model, data) { function(number, model, data) {
if (model === 'dc') {
doc.cookie = `CONSUL_DATACENTER_LOCAL=${data[0]}`;
}
return create(number, model, data); return create(number, model, data);
} }
) )