Skip to content

Commit

Permalink
Merge branch 'bugfix/path-config' into q/2.9
Browse files Browse the repository at this point in the history
  • Loading branch information
bert-e committed Apr 14, 2021
2 parents 511ba0d + 73c0adb commit 852af4a
Show file tree
Hide file tree
Showing 10 changed files with 156 additions and 42 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@

- Bump Node.js version to 14.16.0 (PR[#3214](https://github.com/scality/metalk8s/pull/3214))

- Introduces a `shell-ui` project that groups various UI components to be reused by
solutions UIs (PR[#3106](https://github.com/scality/metalk8s/pull/3106))

- Move the navbar component to `shell-ui` to enable its reuse by solutions UIs
(PR[#3110](https://github.com/scality/metalk8s/pull/3110))

- Add a static user/groups mapping configuration as part of `shell-ui` configuration to
allow solutions UIs displaying features according to some user groups
(PR[#3154](https://github.com/scality/metalk8s/pull/3154))

## Release 2.8.1 (in development)
### Enhancements

Expand Down
2 changes: 1 addition & 1 deletion docs/operation/cluster_and_service_configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ The default configuration values for Dex are specified below:

.. literalinclude:: ../../salt/metalk8s/addons/dex/config/dex.yaml.j2
:language: yaml
:lines: 3-42,45-
:lines: 14-42,45-

See :ref:`csc-dex-customization` for Dex configuration customizations.

Expand Down
13 changes: 12 additions & 1 deletion salt/metalk8s/addons/dex/config/dex.yaml.j2
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
#!jinja|yaml

{%- set metalk8s_ui_defaults = salt.slsutil.renderer(
'salt://metalk8s/addons/ui/config/metalk8s-ui-config.yaml', saltenv=saltenv
)
%}

{%- set metalk8s_ui_config = salt.metalk8s_service_configuration.get_service_conf(
'metalk8s-ui', 'metalk8s-ui-config', metalk8s_ui_defaults
)
%}


# Defaults for configuration of Dex (OIDC)
apiVersion: addons.metalk8s.scality.com/v1alpha2
kind: DexConfig
Expand Down Expand Up @@ -54,7 +65,7 @@ spec:
- id: metalk8s-ui
name: MetalK8s UI
redirectURIs:
- https://{{ grains.metalk8s.control_plane_ip }}:8443/
- https://{{ grains.metalk8s.control_plane_ip }}:8443/{{ metalk8s_ui_config.spec.basePath.lstrip('/') }}
secret: ybrMJpVMQxsiZw26MhJzCjA2ut
- id: grafana-ui
name: Grafana UI
Expand Down
25 changes: 19 additions & 6 deletions salt/metalk8s/addons/ui/config/metalk8s-shell-ui-config.yaml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,28 @@

{%- set dex_defaults = salt.slsutil.renderer('salt://metalk8s/addons/dex/config/dex.yaml.j2', saltenv=saltenv) %}
{%- set dex = salt.metalk8s_service_configuration.get_service_conf('metalk8s-auth', 'metalk8s-dex-config', dex_defaults) %}
{%- set metalk8s_ui_defaults = salt.slsutil.renderer(
'salt://metalk8s/addons/ui/config/metalk8s-ui-config.yaml', saltenv=saltenv
)
%}

{%- set metalk8s_ui_config = salt.metalk8s_service_configuration.get_service_conf(
'metalk8s-ui', 'metalk8s-ui-config', metalk8s_ui_defaults
)
%}

{%- set normalized_base_path = metalk8s_ui_config.spec.basePath.strip('/') %}

{%- set metalk8s_ui_url = "https://" ~ grains.metalk8s.control_plane_ip ~
":8443" ~ ('/' ~ normalized_base_path if normalized_base_path else '') ~ '/' %}

# Defaults for shell UI configuration
apiVersion: addons.metalk8s.scality.com/v1alpha1
kind: ShellUIConfig
spec:
oidc:
providerUrl: "/oidc"
redirectUrl: "https://{{ grains.metalk8s.control_plane_ip }}:8443/"
redirectUrl: "https://{{ grains.metalk8s.control_plane_ip }}:8443/{{ metalk8s_ui_config.spec.basePath.lstrip('/') }}"
clientId: "metalk8s-ui"
responseType: "id_token"
scopes: "openid profile email groups offline_access audience:server:client_id:oidc-auth-client"
Expand All @@ -25,17 +39,16 @@ spec:
canChangeTheme: false
options:
main:
"https://{{ grains.metalk8s.control_plane_ip }}:8443/":
"{{ metalk8s_ui_url }}":
en: "Platform"
fr: "Plateforme"
groups: [metalk8s:admin]
activeIfMatches: "https://{{ grains.metalk8s.control_plane_ip }}:8443/(?!alerts).*"
"https://{{ grains.metalk8s.control_plane_ip }}:8443/alerts":
activeIfMatches: "{{ metalk8s_ui_url }}(?!alerts|docs).*"
"{{ metalk8s_ui_url }}alerts":
en: "Alerts"
fr: "Alertes"
groups: [metalk8s:admin]
subLogin:
"https://{{ grains.metalk8s.control_plane_ip }}:8443/docs":
"{{ metalk8s_ui_url }}docs":
en: "Documentation"
fr: "Documentation"

30 changes: 13 additions & 17 deletions salt/metalk8s/addons/ui/deployed/ingress.sls
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
)
%}

{%- set stripped_base_path = metalk8s_ui_config.spec.basePath.strip('/') %}
{%- set normalized_base_path = '/' ~ stripped_base_path %}

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
Expand Down Expand Up @@ -92,23 +95,16 @@ spec:
rules:
- http:
paths:
- path: {{ metalk8s_ui_config.spec.basePath }}
backend:
serviceName: metalk8s-ui
servicePort: 80
- path: /config.json
backend:
serviceName: metalk8s-ui
servicePort: 80
- path: /brand
backend:
serviceName: metalk8s-ui
servicePort: 80
- path: /static
backend:
serviceName: metalk8s-ui
servicePort: 80
- path: /manifest.json
{% for path in [
"/brand",
"/config.json",
"/manifest.json",
"/shell",
"/static",
normalized_base_path
] %}
- path: {{ path }}
backend:
serviceName: metalk8s-ui
servicePort: 80
{% endfor %}
5 changes: 4 additions & 1 deletion salt/metalk8s/addons/ui/deployed/ui.sls.in
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ include:
)
%}

{%- set stripped_base_path = metalk8s_ui_config.spec.basePath.strip('/') %}
{%- set normalized_base_path = '/' ~ stripped_base_path %}

Create metalk8s-ui deployment:
metalk8s_kubernetes.object_present:
- name: salt://{{ slspath }}/files/metalk8s-ui-deployment.yaml.j2
Expand Down Expand Up @@ -69,7 +72,7 @@ Create metalk8s-ui ConfigMap:
"url_alertmanager": "/api/alertmanager",
"url_navbar": "/shell/solution-ui-navbar.@@ShellUIVersion.js",
"url_navbar_config": "/shell/config.json",
"ui_base_path": "{{ metalk8s_ui_config.spec.basePath }}"
"ui_base_path": "{{ normalized_base_path }}"
}

Create shell-ui ConfigMap:
Expand Down
44 changes: 32 additions & 12 deletions shell-ui/babel.config.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,36 @@
if (process.env.NODE_ENV === "test") {
if (process.env.NODE_ENV === 'test') {
module.exports = {
"presets": ["@babel/preset-env", "@babel/preset-flow", ["@babel/preset-react", {
"runtime": "automatic"
}]],
"plugins": ["@babel/plugin-transform-modules-commonjs"]
}
presets: [
'@babel/preset-env',
'@babel/preset-flow',
[
'@babel/preset-react',
{
runtime: 'automatic',
},
],
],
plugins: ['@babel/plugin-transform-modules-commonjs'],
};
} else {
module.exports = {
"presets": ["@babel/preset-env", "@babel/preset-flow", ["@babel/preset-react", {
"runtime": "automatic"
}]]
}

plugins: [
[
'babel-plugin-styled-components',
{
namespace: 'shell-ui',
},
],
],
presets: [
'@babel/preset-env',
'@babel/preset-flow',
[
'@babel/preset-react',
{
runtime: 'automatic',
},
],
],
};
}

1 change: 1 addition & 0 deletions shell-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"@testing-library/user-event": "^13.0.10",
"babel-jest": "^26.6.3",
"babel-loader": "^8.2.2",
"babel-plugin-styled-components": "^1.12.0",
"css-loader": "^5.0.1",
"flow-bin": "^0.143.1",
"html-webpack-plugin": "^4.5.1",
Expand Down
66 changes: 63 additions & 3 deletions shell-ui/src/Navbar.spec.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { setupServer } from 'msw/node';
import { rest } from 'msw';
import { screen, render, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event'
import userEvent from '@testing-library/user-event';
import './index';
import { waitForLoadingToFinish } from './__TESTS__/utils';
import { jest } from '@jest/globals';

const server = setupServer(
rest.get(
Expand Down Expand Up @@ -43,6 +44,25 @@ const server = setupServer(
),
);

function mockOidcReact() {
const {jest} = require('@jest/globals');

const original = jest.requireActual('oidc-react');
return {
...original, //Pass down all the exported objects
useAuth: () => ({
userData: {
profile: {
groups: ['group1'],
email: '[email protected]',
name: 'user',
},
},
})
}
}
jest.mock('oidc-react', () => mockOidcReact());

const mockOIDCProvider = () => {
// This is a hack to workarround the following issue : MSW return lower cased content-type header,
// oidc-client is internally using XMLHttpRequest to perform queries and retrieve response header Content-Type using 'XMLHttpRequest.prototype.getResponseHeader'.
Expand All @@ -62,6 +82,9 @@ describe('navbar', () => {
jest.useFakeTimers();

beforeAll(() => server.listen());
beforeEach(() => {
jest.resetModules();
});
afterEach(() => server.resetHandlers());

it('should display a loading state when resolving its configuration', () => {
Expand All @@ -87,7 +110,7 @@ describe('navbar', () => {
return res(ctx.status(500));
}),
);

render(
<solutions-navbar
oidc-provider-url="https://mocked.ingress/oidc"
Expand All @@ -109,6 +132,7 @@ describe('navbar', () => {
it('should display expected selected menu when it matches by exact loaction (default behavior)', async () => {
//S
mockOIDCProvider();

//E
render(
<solutions-navbar
Expand Down Expand Up @@ -138,6 +162,7 @@ describe('navbar', () => {
it('should display expected selected menu when it matches by regex', async () => {
//S
mockOIDCProvider();

//E
render(
<solutions-navbar
Expand Down Expand Up @@ -171,6 +196,7 @@ describe('navbar', () => {
it('should set the language of the navbar', async () => {
//S
mockOIDCProvider();

//E
render(
<solutions-navbar
Expand Down Expand Up @@ -208,7 +234,7 @@ describe('navbar', () => {
});
expect(platformEntry).toBeInTheDocument();
expect(localStorage.setItem).toBeCalledWith('lang', 'fr');

//C
userEvent.click(screen.getByText('en'));
});
Expand All @@ -224,6 +250,7 @@ describe('navbar', () => {

mockOIDCProvider();


render(
<solutions-navbar
oidc-provider-url="https://mocked.ingress/oidc"
Expand Down Expand Up @@ -252,6 +279,7 @@ describe('navbar', () => {

mockOIDCProvider();


render(
<solutions-navbar
oidc-provider-url="https://mocked.ingress/oidc"
Expand Down Expand Up @@ -279,5 +307,37 @@ describe('navbar', () => {
expect(screen.queryByText(/Test/i)).not.toBeInTheDocument();
});

it('should display a restrained menu when an user is authorized', async () => {
//S

mockOIDCProvider();

render(
<solutions-navbar
oidc-provider-url="https://mocked.ingress/oidc"
client-id="metalk8s-ui"
response-type="id_token"
redirect-url="http://localhost:8082"
scopes="openid profile email groups offline_access audience:server:client_id:oidc-auth-client"
options={JSON.stringify({
main: {
'http://localhost:8082/': { en: 'Platform', fr: 'Plateforme' },
'http://localhost:8082/test': {
en: 'Test',
fr: 'Test',
groups: ['group1', 'group2'],
},
},
subLogin: {},
})}
/>,
);
//E
await waitForLoadingToFinish();
//V
expect(screen.queryByText(/Platform/i)).toBeInTheDocument();
expect(screen.queryByText(/Test/i)).toBeInTheDocument();
});

afterAll(() => server.close());
});
2 changes: 1 addition & 1 deletion shell-ui/src/auth/permissionUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const isEntryAccessibleByTheUser = (
userGroups: string[],
): boolean => {
return (
pathDescription.groups?.every((group) => userGroups.includes(group)) ??
pathDescription.groups?.some((group) => userGroups.includes(group)) ??
true
);
};
Expand Down

0 comments on commit 852af4a

Please sign in to comment.