1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

release v5.5.2 (#5504)

Co-authored-by: Lauri Nevala <lauri.nevala@gmail.com>
Co-authored-by: Roman <ixrock@gmail.com>
This commit is contained in:
Sebastian Malton 2022-05-30 11:15:51 -07:00 committed by GitHub
parent 07e9456874
commit e3cb23e111
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 875 additions and 69 deletions

View File

@ -24,11 +24,6 @@ spec:
operator: In
values:
- linux
- matchExpressions:
- key: beta.kubernetes.io/os
operator: In
values:
- linux
# <%- if config.node_selector -%>
# nodeSelector:
# <%- node_selector.to_h.each do |key, value| -%>

View File

@ -30,11 +30,6 @@ spec:
operator: In
values:
- linux
- matchExpressions:
- key: beta.kubernetes.io/os
operator: In
values:
- linux
securityContext:
runAsNonRoot: true
runAsUser: 65534

View File

@ -23,11 +23,6 @@ spec:
operator: In
values:
- linux
- matchExpressions:
- key: beta.kubernetes.io/os
operator: In
values:
- linux
serviceAccountName: kube-state-metrics
containers:
- name: kube-state-metrics

View File

@ -3,7 +3,7 @@
"productName": "OpenLens",
"description": "OpenLens - Open Source IDE for Kubernetes",
"homepage": "https://github.com/lensapp/lens",
"version": "5.5.1",
"version": "5.5.2",
"main": "static/build/main.js",
"copyright": "© 2021 OpenLens Authors",
"license": "MIT",
@ -72,6 +72,9 @@
"<rootDir>/src/jest.setup.ts",
"jest-canvas-mock"
],
"setupFilesAfterEnv": [
"<rootDir>/src/jest-after-env.setup.ts"
],
"globals": {
"ts-jest": {
"isolatedModules": true

View File

@ -279,8 +279,10 @@ export interface CephfsSource {
secretRef?: SecretReference;
/**
* Whether the filesystem is used as readOnly.
*
* @default false
*/
readOnly: boolean;
readOnly?: boolean;
}
export interface CinderSource {
@ -430,46 +432,62 @@ export interface PortworxVolumeSource {
readOnly?: boolean;
}
export interface ProjectedSource {
sources: {
secret?: {
name: string;
items?: {
export interface KeyToPath {
key: string;
path: string;
mode?: number;
}[];
};
downwardAPI?: {
items?: {
path: string;
fieldRef?: {
}
export interface ConfigMapProjection {
name: string;
items?: KeyToPath[];
optional?: boolean;
}
export interface ObjectFieldSelector {
fieldPath: string;
apiVersion?: string;
};
resourceFieldRef?: {
}
export interface ResourceFieldSelector {
resource: string;
containerName?: string;
};
mode?: number;
}[];
};
configMap?: {
name: string;
items?: {
key: string;
divisor?: string;
}
export interface DownwardAPIVolumeFile {
path: string;
fieldRef?: ObjectFieldSelector;
resourceFieldRef?: ResourceFieldSelector;
mode?: number;
}[];
}
export interface DownwardAPIProjection {
items?: DownwardAPIVolumeFile[];
}
export interface SecretProjection {
name: string;
items?: KeyToPath[];
optional?: boolean;
};
serviceAccountToken?: {
}
export interface ServiceAccountTokenProjection {
audience?: string;
expirationSeconds?: number;
path: string;
};
}[];
defaultMode: number;
}
export interface VolumeProjection {
secret?: SecretProjection;
downwardAPI?: DownwardAPIProjection;
configMap?: ConfigMapProjection;
serviceAccountToken?: ServiceAccountTokenProjection;
}
export interface ProjectedSource {
sources?: VolumeProjection[];
defaultMode?: number;
}
export interface QuobyteSource {

View File

@ -43,6 +43,7 @@ export interface KubeJsonApiData extends JsonApiData {
kind: string;
apiVersion: string;
metadata: KubeJsonApiMetadata;
spec?: unknown;
}
export interface KubeJsonApiError extends JsonApiError {

View File

@ -0,0 +1,5 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import "@testing-library/jest-dom/extend-expect";

View File

@ -0,0 +1,229 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<Projected /> renders 1`] = `
<body>
<div>
<div
class="DrawerItem"
>
<span
class="name"
>
Sources
</span>
<span
class="value"
/>
</div>
</div>
</body>
`;
exports[`<Projected /> renders a secret source including overriding mode 1`] = `
<body>
<div>
<div
class="DrawerItem"
>
<span
class="name"
>
Default Mount Mode
</span>
<span
class="value"
>
0o777
</span>
</div>
<div
class="DrawerItem"
>
<span
class="name"
>
Sources
</span>
<span
class="value"
>
<div
class="DrawerTitle sub-title"
>
Secret
</div>
<div
class="DrawerItem"
>
<span
class="name"
>
Name
</span>
<span
class="value"
>
my-projected-secret
</span>
</div>
<div
class="DrawerItem"
>
<span
class="name"
>
Items
</span>
<span
class="value"
>
<ul>
<li>
foo⇢/bar
(0o666)
</li>
</ul>
</span>
</div>
</span>
</div>
</div>
</body>
`;
exports[`<Projected /> renders a secret source, when provided 1`] = `
<body>
<div>
<div
class="DrawerItem"
>
<span
class="name"
>
Default Mount Mode
</span>
<span
class="value"
>
0o777
</span>
</div>
<div
class="DrawerItem"
>
<span
class="name"
>
Sources
</span>
<span
class="value"
>
<div
class="DrawerTitle sub-title"
>
Secret
</div>
<div
class="DrawerItem"
>
<span
class="name"
>
Name
</span>
<span
class="value"
>
my-projected-secret
</span>
</div>
<div
class="DrawerItem"
>
<span
class="name"
>
Items
</span>
<span
class="value"
>
<ul>
<li>
foo⇢/bar
</li>
</ul>
</span>
</div>
</span>
</div>
</div>
</body>
`;
exports[`<Projected /> renders default mount mode in octal when provided 1`] = `
<body>
<div>
<div
class="DrawerItem"
>
<span
class="name"
>
Default Mount Mode
</span>
<span
class="value"
>
0o777
</span>
</div>
<div
class="DrawerItem"
>
<span
class="name"
>
Sources
</span>
<span
class="value"
/>
</div>
</div>
</body>
`;
exports[`<Projected /> renders when no sources array provided 1`] = `
<body>
<div>
<div
class="DrawerItem"
>
<span
class="name"
>
Default Mount Mode
</span>
<span
class="value"
>
0o777
</span>
</div>
<div
class="DrawerItem"
>
<span
class="name"
>
Sources
</span>
<span
class="value"
/>
</div>
</div>
</body>
`;

View File

@ -0,0 +1,229 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<CephFs /> should render 'false' for Readonly when false is provided 1`] = `
<div>
<div
class="DrawerItem"
>
<span
class="name"
>
Monitors
</span>
<span
class="value"
>
<ul />
</span>
</div>
<div
class="DrawerItem"
>
<span
class="name"
>
Mount Path
</span>
<span
class="value"
>
/
</span>
</div>
<div
class="DrawerItem"
>
<span
class="name"
>
Username
</span>
<span
class="value"
>
admin
</span>
</div>
<div
class="DrawerItem"
>
<span
class="name"
>
Secret Filepath
</span>
<span
class="value"
>
/etc/ceph/user.secret
</span>
</div>
<div
class="DrawerItem"
data-testid="cephfs-readonly"
>
<span
class="name"
>
Readonly
</span>
<span
class="value"
>
false
</span>
</div>
</div>
`;
exports[`<CephFs /> should render 'false' for Readonly when not provided 1`] = `
<div>
<div
class="DrawerItem"
>
<span
class="name"
>
Monitors
</span>
<span
class="value"
>
<ul />
</span>
</div>
<div
class="DrawerItem"
>
<span
class="name"
>
Mount Path
</span>
<span
class="value"
>
/
</span>
</div>
<div
class="DrawerItem"
>
<span
class="name"
>
Username
</span>
<span
class="value"
>
admin
</span>
</div>
<div
class="DrawerItem"
>
<span
class="name"
>
Secret Filepath
</span>
<span
class="value"
>
/etc/ceph/user.secret
</span>
</div>
<div
class="DrawerItem"
data-testid="cephfs-readonly"
>
<span
class="name"
>
Readonly
</span>
<span
class="value"
>
false
</span>
</div>
</div>
`;
exports[`<CephFs /> should render 'true' for Readonly when true is provided 1`] = `
<div>
<div
class="DrawerItem"
>
<span
class="name"
>
Monitors
</span>
<span
class="value"
>
<ul />
</span>
</div>
<div
class="DrawerItem"
>
<span
class="name"
>
Mount Path
</span>
<span
class="value"
>
/
</span>
</div>
<div
class="DrawerItem"
>
<span
class="name"
>
Username
</span>
<span
class="value"
>
admin
</span>
</div>
<div
class="DrawerItem"
>
<span
class="name"
>
Secret Filepath
</span>
<span
class="value"
>
/etc/ceph/user.secret
</span>
</div>
<div
class="DrawerItem"
data-testid="cephfs-readonly"
>
<span
class="name"
>
Readonly
</span>
<span
class="value"
>
true
</span>
</div>
</div>
`;

View File

@ -0,0 +1,116 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { render } from "@testing-library/react";
import React from "react";
import type { CephfsSource } from "../../../../../../../common/k8s-api/endpoints";
import { Pod } from "../../../../../../../common/k8s-api/endpoints";
import { CephFs } from "../ceph-fs";
describe("<CephFs />", () => {
it("should render 'false' for Readonly when not provided", () => {
const cephfsName = "my-ceph";
const cephfsVolume: CephfsSource = {
monitors: [],
};
const pod = new Pod({
apiVersion: "v1",
kind: "Pod",
metadata: {
name: "my-pod",
namespace: "default",
resourceVersion: "1",
uid: "123",
selfLink: "/api/v1/pod/default/my-pod",
},
spec: {
volumes: [{
name: cephfsName,
cephfs: cephfsVolume,
}],
},
});
const result = render((
<CephFs
pod={pod}
variant={cephfsVolume}
volumeName={cephfsName}
/>
));
expect(result.container).toMatchSnapshot();
expect(result.getByTestId("cephfs-readonly")).toHaveTextContent("false");
});
it("should render 'false' for Readonly when false is provided", () => {
const cephfsName = "my-ceph";
const cephfsVolume: CephfsSource = {
monitors: [],
readOnly: false,
};
const pod = new Pod({
apiVersion: "v1",
kind: "Pod",
metadata: {
name: "my-pod",
namespace: "default",
resourceVersion: "1",
uid: "123",
selfLink: "/api/v1/pod/default/my-pod",
},
spec: {
volumes: [{
name: cephfsName,
cephfs: cephfsVolume,
}],
},
});
const result = render((
<CephFs
pod={pod}
variant={cephfsVolume}
volumeName={cephfsName}
/>
));
expect(result.container).toMatchSnapshot();
expect(result.getByTestId("cephfs-readonly")).toHaveTextContent("false");
});
it("should render 'true' for Readonly when true is provided", () => {
const cephfsName = "my-ceph";
const cephfsVolume: CephfsSource = {
monitors: [],
readOnly: true,
};
const pod = new Pod({
apiVersion: "v1",
kind: "Pod",
metadata: {
name: "my-pod",
namespace: "default",
resourceVersion: "1",
uid: "123",
selfLink: "/api/v1/pod/default/my-pod",
},
spec: {
volumes: [{
name: cephfsName,
cephfs: cephfsVolume,
}],
},
});
const result = render((
<CephFs
pod={pod}
variant={cephfsVolume}
volumeName={cephfsName}
/>
));
expect(result.container).toMatchSnapshot();
expect(result.getByTestId("cephfs-readonly")).toHaveTextContent("true");
});
});

View File

@ -10,7 +10,7 @@ import type { VolumeVariantComponent } from "../variant-helpers";
import { LocalRef } from "../variant-helpers";
export const CephFs: VolumeVariantComponent<"cephfs"> = (
({ pod, variant: { monitors, path = "/", user = "admin", secretFile = "/etc/ceph/user.secret", secretRef, readOnly }}) => (
({ pod, variant: { monitors, path = "/", user = "admin", secretFile = "/etc/ceph/user.secret", secretRef, readOnly = false }}) => (
<>
<DrawerItem name="Monitors">
<ul>
@ -39,7 +39,7 @@ export const CephFs: VolumeVariantComponent<"cephfs"> = (
</DrawerItem>
)
}
<DrawerItem name="Readonly">
<DrawerItem name="Readonly" data-testid="cephfs-readonly">
{readOnly.toString()}
</DrawerItem>
</>

View File

@ -0,0 +1,197 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { render } from "@testing-library/react";
import React from "react";
import type { ProjectedSource } from "../../../../../../common/k8s-api/endpoints";
import { Pod } from "../../../../../../common/k8s-api/endpoints";
import { Projected } from "./projected";
describe("<Projected />", () => {
it("renders", () => {
const projectedVolume: ProjectedSource = { };
const projectedVolumeName = "my-projected";
const pod = new Pod({
apiVersion: "v1",
kind: "Pod",
metadata: {
name: "my-pod",
namespace: "default",
resourceVersion: "1",
uid: "123",
selfLink: "/api/v1/pod/default/my-pod",
},
spec: {
volumes: [{
name: projectedVolumeName,
projected: projectedVolume,
}],
},
});
const result = render((
<Projected
pod={pod}
volumeName={projectedVolumeName}
variant={projectedVolume}
/>
));
expect(result.baseElement).toMatchSnapshot();
});
it("renders default mount mode in octal when provided", () => {
const projectedVolume: ProjectedSource = {
defaultMode: 0o777,
sources: [],
};
const projectedVolumeName = "my-projected";
const pod = new Pod({
apiVersion: "v1",
kind: "Pod",
metadata: {
name: "my-pod",
namespace: "default",
resourceVersion: "1",
uid: "123",
selfLink: "/api/v1/pod/default/my-pod",
},
spec: {
volumes: [{
name: projectedVolumeName,
projected: projectedVolume,
}],
},
});
const result = render((
<Projected
pod={pod}
volumeName={projectedVolumeName}
variant={projectedVolume}
/>
));
expect(result.baseElement).toMatchSnapshot();
});
it("renders when no sources array provided", () => {
const projectedVolume: ProjectedSource = {
defaultMode: 0o777,
};
const projectedVolumeName = "my-projected";
const pod = new Pod({
apiVersion: "v1",
kind: "Pod",
metadata: {
name: "my-pod",
namespace: "default",
resourceVersion: "1",
uid: "123",
selfLink: "/api/v1/pod/default/my-pod",
},
spec: {
volumes: [{
name: projectedVolumeName,
projected: projectedVolume,
}],
},
});
const result = render((
<Projected
pod={pod}
volumeName={projectedVolumeName}
variant={projectedVolume}
/>
));
expect(result.baseElement).toMatchSnapshot();
});
it("renders a secret source, when provided", () => {
const projectedVolume: ProjectedSource = {
defaultMode: 0o777,
sources: [{
secret: {
name: "my-projected-secret",
items: [{
key: "foo",
path: "/bar",
}],
},
}],
};
const projectedVolumeName = "my-projected";
const pod = new Pod({
apiVersion: "v1",
kind: "Pod",
metadata: {
name: "my-pod",
namespace: "default",
resourceVersion: "1",
uid: "123",
selfLink: "/api/v1/pod/default/my-pod",
},
spec: {
volumes: [{
name: projectedVolumeName,
projected: projectedVolume,
}],
},
});
const result = render((
<Projected
pod={pod}
volumeName={projectedVolumeName}
variant={projectedVolume}
/>
));
expect(result.baseElement).toMatchSnapshot();
expect(result.getByText("foo⇢/bar", { exact: false })).toBeTruthy();
});
it("renders a secret source including overriding mode", () => {
const projectedVolume: ProjectedSource = {
defaultMode: 0o777,
sources: [{
secret: {
name: "my-projected-secret",
items: [{
key: "foo",
path: "/bar",
mode: 0o666,
}],
},
}],
};
const projectedVolumeName = "my-projected";
const pod = new Pod({
apiVersion: "v1",
kind: "Pod",
metadata: {
name: "my-pod",
namespace: "default",
resourceVersion: "1",
uid: "123",
selfLink: "/api/v1/pod/default/my-pod",
},
spec: {
volumes: [{
name: projectedVolumeName,
projected: projectedVolume,
}],
},
});
const result = render((
<Projected
pod={pod}
volumeName={projectedVolumeName}
variant={projectedVolume}
/>
));
expect(result.baseElement).toMatchSnapshot();
expect(result.getByText("(0o666)", { exact: false })).toBeTruthy();
});
});

View File

@ -4,18 +4,21 @@
*/
import React from "react";
import { displayMode } from "../../../../../utils";
import { DrawerItem, DrawerTitle } from "../../../../drawer";
import type { VolumeVariantComponent } from "../variant-helpers";
export const Projected: VolumeVariantComponent<"projected"> = (
({ variant: { sources, defaultMode }}) => (
<>
{typeof defaultMode === "number" && (
<DrawerItem name="Default Mount Mode">
0o{defaultMode.toString(8)}
{displayMode(defaultMode)}
</DrawerItem>
)}
<DrawerItem name="Sources">
{
sources.map(({ secret, downwardAPI, configMap, serviceAccountToken }, index) => (
sources?.map(({ secret, downwardAPI, configMap, serviceAccountToken }, index) => (
<React.Fragment key={index}>
{secret && (
<>
@ -25,9 +28,12 @@ export const Projected: VolumeVariantComponent<"projected"> = (
</DrawerItem>
<DrawerItem name="Items">
<ul>
{secret.items?.map(({ key, path }) => (
{secret.items?.map(({ key, path, mode }) => (
<li key={key}>
{key} {path}
{`${key}${path}`}
{typeof mode === "number" && (
` (${displayMode(mode)})`
)}
</li>
))}
</ul>

View File

@ -14,7 +14,6 @@ import { debounce, merge } from "lodash";
import { autoBind, cssNames, disposer } from "../../utils";
import { UserStore } from "../../../common/user-store";
import { ThemeStore } from "../../theme.store";
import logger from "../../../main/logger";
export type MonacoEditorId = string;
@ -60,6 +59,12 @@ export class MonacoEditor extends React.Component<MonacoEditorProps> {
@observable readonly dimensions: { width?: number; height?: number } = {};
@observable private unmounting = false;
// TODO: investigate how to replace with "common/logger"
// currently leads for stucking UI forever & infinite loop.
// e.g. happens on tab change/create, maybe some other cases too.
private logger = console;
constructor(props: MonacoEditorProps) {
super(props);
makeObservable(this);
@ -119,7 +124,7 @@ export class MonacoEditor extends React.Component<MonacoEditorProps> {
}
protected onModelChange(model: editor.ITextModel, oldModel?: editor.ITextModel) {
logger.info("[MONACO]: model change", { model, oldModel }, this.logMetadata);
this.logger.info("[MONACO]: model change", { model, oldModel }, this.logMetadata);
if (oldModel) {
this.saveViewState(oldModel);
@ -152,9 +157,9 @@ export class MonacoEditor extends React.Component<MonacoEditorProps> {
componentDidMount() {
try {
this.createEditor();
logger.info(`[MONACO]: editor did mount`, this.logMetadata);
this.logger.info(`[MONACO]: editor did mount`, this.logMetadata);
} catch (error) {
logger.error(`[MONACO]: mounting failed: ${error}`, this.logMetadata);
this.logger.error(`[MONACO]: mounting failed: ${error}`, this.logMetadata);
}
}
@ -180,7 +185,7 @@ export class MonacoEditor extends React.Component<MonacoEditorProps> {
...this.options,
});
logger.info(`[MONACO]: editor created for language=${language}, theme=${theme}`, this.logMetadata);
this.logger.info(`[MONACO]: editor created for language=${language}, theme=${theme}`, this.logMetadata);
this.validateLazy(); // validate initial value
this.restoreViewState(this.model); // restore previous state if any

View File

@ -0,0 +1,11 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
/**
* Format `mode` in octal notation
*/
export function displayMode(mode: number): string {
return `0o${mode.toString(8)}`;
}

View File

@ -10,6 +10,7 @@ export * from "../../common/event-emitter";
export * from "./cssNames";
export * from "./cssVar";
export * from "./display-booleans";
export * from "./display-mode";
export * from "./interval";
export * from "./isMiddleClick";
export * from "./isReactNode";