mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Replace resource applier with injectables
Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
35f3c08279
commit
1809f98046
@ -1,38 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import yaml from "js-yaml";
|
|
||||||
import type { KubeJsonApiData } from "../kube-json-api";
|
|
||||||
import { apiBase } from "../index";
|
|
||||||
import type { Patch } from "rfc6902";
|
|
||||||
|
|
||||||
export const annotations = [
|
|
||||||
"kubectl.kubernetes.io/last-applied-configuration",
|
|
||||||
];
|
|
||||||
|
|
||||||
export async function update(resource: object | string): Promise<KubeJsonApiData> {
|
|
||||||
if (typeof resource === "string") {
|
|
||||||
const parsed = yaml.load(resource);
|
|
||||||
|
|
||||||
if (!parsed || typeof parsed !== "object") {
|
|
||||||
throw new Error("Cannot update resource to string or number");
|
|
||||||
}
|
|
||||||
|
|
||||||
resource = parsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
return apiBase.post<KubeJsonApiData>("/stack", { data: resource });
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function patch(name: string, kind: string, ns: string | undefined, patch: Patch): Promise<KubeJsonApiData> {
|
|
||||||
return apiBase.patch<KubeJsonApiData>("/stack", {
|
|
||||||
data: {
|
|
||||||
name,
|
|
||||||
kind,
|
|
||||||
ns,
|
|
||||||
patch,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import type { Patch } from "rfc6902";
|
||||||
|
import { apiBaseInjectionToken } from "../../api-base";
|
||||||
|
import type { KubeJsonApiData } from "../../kube-json-api";
|
||||||
|
|
||||||
|
export type RequestKubeObjectPatch = (name: string, kind: string, ns: string | undefined, patch: Patch) => Promise<KubeJsonApiData>;
|
||||||
|
|
||||||
|
const requestKubeObjectPatchInjectable = getInjectable({
|
||||||
|
id: "request-kube-object-patch",
|
||||||
|
instantiate: (di): RequestKubeObjectPatch => {
|
||||||
|
const apiBase = di.inject(apiBaseInjectionToken);
|
||||||
|
|
||||||
|
return (name, kind, ns, patch) => (
|
||||||
|
apiBase.patch("/stack", {
|
||||||
|
data: {
|
||||||
|
name,
|
||||||
|
kind,
|
||||||
|
ns,
|
||||||
|
patch,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default requestKubeObjectPatchInjectable;
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import { apiBaseInjectionToken } from "../../api-base";
|
||||||
|
import type { KubeJsonApiData } from "../../kube-json-api";
|
||||||
|
|
||||||
|
export type RequestKubeObjectCreation = (resourceDescriptor: string) => Promise<KubeJsonApiData>;
|
||||||
|
|
||||||
|
const requestKubeObjectCreationInjectable = getInjectable({
|
||||||
|
id: "request-kube-object-creation",
|
||||||
|
instantiate: (di): RequestKubeObjectCreation => {
|
||||||
|
const apiBase = di.inject(apiBaseInjectionToken);
|
||||||
|
|
||||||
|
return (data) => apiBase.post("/stack", { data });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default requestKubeObjectCreationInjectable;
|
||||||
@ -9,11 +9,15 @@ import moment from "moment";
|
|||||||
import type { KubeJsonApiData, KubeJsonApiDataList, KubeJsonApiListMetadata } from "./kube-json-api";
|
import type { KubeJsonApiData, KubeJsonApiDataList, KubeJsonApiListMetadata } from "./kube-json-api";
|
||||||
import { autoBind, formatDuration, hasOptionalTypedProperty, hasTypedProperty, isObject, isString, isNumber, bindPredicate, isTypedArray, isRecord, json } from "../utils";
|
import { autoBind, formatDuration, hasOptionalTypedProperty, hasTypedProperty, isObject, isString, isNumber, bindPredicate, isTypedArray, isRecord, json } from "../utils";
|
||||||
import type { ItemObject } from "../item.store";
|
import type { ItemObject } from "../item.store";
|
||||||
import { apiKube } from "./index";
|
|
||||||
import * as resourceApplierApi from "./endpoints/resource-applier.api";
|
|
||||||
import type { Patch } from "rfc6902";
|
import type { Patch } from "rfc6902";
|
||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import type { JsonObject } from "type-fest";
|
import type { JsonObject } from "type-fest";
|
||||||
|
import { asLegacyGlobalFunctionForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-function-for-extension-api";
|
||||||
|
import requestKubeObjectPatchInjectable from "./endpoints/resource-applier.api/patch.injectable";
|
||||||
|
import { asLegacyGlobalForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api";
|
||||||
|
import { apiKubeInjectionToken } from "./api-kube";
|
||||||
|
import requestKubeObjectCreationInjectable from "./endpoints/resource-applier.api/update.injectable";
|
||||||
|
import { dump } from "js-yaml";
|
||||||
|
|
||||||
export type KubeJsonApiDataFor<K> = K extends KubeObject<infer Metadata, infer Status, infer Spec>
|
export type KubeJsonApiDataFor<K> = K extends KubeObject<infer Metadata, infer Status, infer Spec>
|
||||||
? KubeJsonApiData<Metadata, Status, Spec>
|
? KubeJsonApiData<Metadata, Status, Spec>
|
||||||
@ -375,6 +379,12 @@ export type ScopedNamespace<Namespaced extends KubeObjectScope> = (
|
|||||||
: string | undefined
|
: string | undefined
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const resourceApplierAnnotationsForFiltering = [
|
||||||
|
"kubectl.kubernetes.io/last-applied-configuration",
|
||||||
|
];
|
||||||
|
|
||||||
|
const filterOutResourceApplierAnnotations = (label: string) => !resourceApplierAnnotationsForFiltering.some(key => label.startsWith(key));
|
||||||
|
|
||||||
export class KubeObject<
|
export class KubeObject<
|
||||||
Metadata extends KubeObjectMetadata<KubeObjectScope> = KubeObjectMetadata<KubeObjectScope>,
|
Metadata extends KubeObjectMetadata<KubeObjectScope> = KubeObjectMetadata<KubeObjectScope>,
|
||||||
Status = unknown,
|
Status = unknown,
|
||||||
@ -588,11 +598,11 @@ export class KubeObject<
|
|||||||
getAnnotations(filter = false): string[] {
|
getAnnotations(filter = false): string[] {
|
||||||
const labels = KubeObject.stringifyLabels(this.metadata.annotations);
|
const labels = KubeObject.stringifyLabels(this.metadata.annotations);
|
||||||
|
|
||||||
return filter ? labels.filter(label => {
|
if (!filter) {
|
||||||
const skip = resourceApplierApi.annotations.some(key => label.startsWith(key));
|
return labels;
|
||||||
|
}
|
||||||
|
|
||||||
return !skip;
|
return labels.filter(filterOutResourceApplierAnnotations);
|
||||||
}) : labels;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getOwnerRefs() {
|
getOwnerRefs() {
|
||||||
@ -634,7 +644,9 @@ export class KubeObject<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return resourceApplierApi.patch(this.getName(), this.kind, this.getNs(), patch);
|
const requestKubeObjectPatch = asLegacyGlobalFunctionForExtensionApi(requestKubeObjectPatchInjectable);
|
||||||
|
|
||||||
|
return requestKubeObjectPatch(this.getName(), this.kind, this.getNs(), patch);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -647,11 +659,13 @@ export class KubeObject<
|
|||||||
* @deprecated use KubeApi.update instead
|
* @deprecated use KubeApi.update instead
|
||||||
*/
|
*/
|
||||||
async update(data: Partial<this>): Promise<KubeJsonApiData | null> {
|
async update(data: Partial<this>): Promise<KubeJsonApiData | null> {
|
||||||
// use unified resource-applier api for updating all k8s objects
|
const requestKubeObjectCreation = asLegacyGlobalFunctionForExtensionApi(requestKubeObjectCreationInjectable);
|
||||||
return resourceApplierApi.update({
|
const descriptor = dump({
|
||||||
...this.toPlainObject(),
|
...this.toPlainObject(),
|
||||||
...data,
|
...data,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return requestKubeObjectCreation(descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -660,6 +674,8 @@ export class KubeObject<
|
|||||||
delete(params?: object) {
|
delete(params?: object) {
|
||||||
assert(this.selfLink, "selfLink must be present to delete self");
|
assert(this.selfLink, "selfLink must be present to delete self");
|
||||||
|
|
||||||
|
const apiKube = asLegacyGlobalForExtensionApi(apiKubeInjectionToken);
|
||||||
|
|
||||||
return apiKube.del(this.selfLink, params);
|
return apiKube.del(this.selfLink, params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,11 +62,10 @@ export class ResourceApplier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async apply(resource: KubernetesObject | any): Promise<string> {
|
async create(resource: string): Promise<string> {
|
||||||
resource = this.sanitizeObject(resource);
|
|
||||||
appEventBus.emit({ name: "resource", action: "apply" });
|
appEventBus.emit({ name: "resource", action: "apply" });
|
||||||
|
|
||||||
return this.kubectlApply(yaml.dump(resource));
|
return this.kubectlApply(yaml.dump(this.sanitizeObject(resource)));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async kubectlApply(content: string): Promise<string> {
|
protected async kubectlApply(content: string): Promise<string> {
|
||||||
@ -154,11 +153,7 @@ export class ResourceApplier {
|
|||||||
|
|
||||||
delete res.status;
|
delete res.status;
|
||||||
delete res.metadata?.resourceVersion;
|
delete res.metadata?.resourceVersion;
|
||||||
const annotations = res.metadata?.annotations;
|
delete res.metadata?.annotations["kubectl.kubernetes.io/last-applied-configuration"];
|
||||||
|
|
||||||
if (annotations) {
|
|
||||||
delete annotations["kubectl.kubernetes.io/last-applied-configuration"];
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,17 +5,19 @@
|
|||||||
import { getRouteInjectable } from "../../router/router.injectable";
|
import { getRouteInjectable } from "../../router/router.injectable";
|
||||||
import { apiPrefix } from "../../../common/vars";
|
import { apiPrefix } from "../../../common/vars";
|
||||||
import { ResourceApplier } from "../../resource-applier";
|
import { ResourceApplier } from "../../resource-applier";
|
||||||
import { clusterRoute } from "../../router/route";
|
import { payloadValidatedClusterRoute } from "../../router/route";
|
||||||
|
import Joi from "joi";
|
||||||
|
|
||||||
const applyResourceRouteInjectable = getRouteInjectable({
|
const createResourceRouteInjectable = getRouteInjectable({
|
||||||
id: "apply-resource-route",
|
id: "apply-resource-route",
|
||||||
|
|
||||||
instantiate: () => clusterRoute({
|
instantiate: () => payloadValidatedClusterRoute({
|
||||||
method: "post",
|
method: "post",
|
||||||
path: `${apiPrefix}/stack`,
|
path: `${apiPrefix}/stack`,
|
||||||
|
payloadValidator: Joi.string(),
|
||||||
})(async ({ cluster, payload }) => ({
|
})(async ({ cluster, payload }) => ({
|
||||||
response: await new ResourceApplier(cluster).apply(payload),
|
response: await new ResourceApplier(cluster).create(payload),
|
||||||
})),
|
})),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default applyResourceRouteInjectable;
|
export default createResourceRouteInjectable;
|
||||||
|
|||||||
@ -6,14 +6,13 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import type { SelectOption } from "../../select";
|
import type { SelectOption } from "../../select";
|
||||||
import { Select } from "../../select";
|
import { Select } from "../../select";
|
||||||
import yaml from "js-yaml";
|
import yaml, { dump } from "js-yaml";
|
||||||
import type { IComputedValue } from "mobx";
|
import type { IComputedValue } from "mobx";
|
||||||
import { makeObservable, observable } from "mobx";
|
import { makeObservable, observable } from "mobx";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import type { CreateResourceTabStore } from "./store";
|
import type { CreateResourceTabStore } from "./store";
|
||||||
import { EditorPanel } from "../editor-panel";
|
import { EditorPanel } from "../editor-panel";
|
||||||
import { InfoPanel } from "../info-panel";
|
import { InfoPanel } from "../info-panel";
|
||||||
import * as resourceApplierApi from "../../../../common/k8s-api/endpoints/resource-applier.api";
|
|
||||||
import { Notifications } from "../../notifications";
|
import { Notifications } from "../../notifications";
|
||||||
import logger from "../../../../common/logger";
|
import logger from "../../../../common/logger";
|
||||||
import type { ApiManager } from "../../../../common/k8s-api/api-manager";
|
import type { ApiManager } from "../../../../common/k8s-api/api-manager";
|
||||||
@ -28,6 +27,8 @@ import type { GetDetailsUrl } from "../../kube-detail-params/get-details-url.inj
|
|||||||
import apiManagerInjectable from "../../../../common/k8s-api/api-manager/manager.injectable";
|
import apiManagerInjectable from "../../../../common/k8s-api/api-manager/manager.injectable";
|
||||||
import getDetailsUrlInjectable from "../../kube-detail-params/get-details-url.injectable";
|
import getDetailsUrlInjectable from "../../kube-detail-params/get-details-url.injectable";
|
||||||
import navigateInjectable from "../../../navigation/navigate.injectable";
|
import navigateInjectable from "../../../navigation/navigate.injectable";
|
||||||
|
import type { RequestKubeObjectCreation } from "../../../../common/k8s-api/endpoints/resource-applier.api/update.injectable";
|
||||||
|
import requestKubeObjectCreationInjectable from "../../../../common/k8s-api/endpoints/resource-applier.api/update.injectable";
|
||||||
|
|
||||||
export interface CreateResourceProps {
|
export interface CreateResourceProps {
|
||||||
tabId: string;
|
tabId: string;
|
||||||
@ -39,6 +40,7 @@ interface Dependencies {
|
|||||||
apiManager: ApiManager;
|
apiManager: ApiManager;
|
||||||
navigate: Navigate;
|
navigate: Navigate;
|
||||||
getDetailsUrl: GetDetailsUrl;
|
getDetailsUrl: GetDetailsUrl;
|
||||||
|
requestKubeObjectCreation: RequestKubeObjectCreation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
@ -68,7 +70,7 @@ class NonInjectedCreateResource extends React.Component<CreateResourceProps & De
|
|||||||
};
|
};
|
||||||
|
|
||||||
create = async (): Promise<void> => {
|
create = async (): Promise<void> => {
|
||||||
const { apiManager, getDetailsUrl, navigate } = this.props;
|
const { apiManager, getDetailsUrl, navigate, requestKubeObjectCreation } = this.props;
|
||||||
|
|
||||||
if (this.error || !this.data?.trim()) {
|
if (this.error || !this.data?.trim()) {
|
||||||
// do not save when field is empty or there is an error
|
// do not save when field is empty or there is an error
|
||||||
@ -84,7 +86,7 @@ class NonInjectedCreateResource extends React.Component<CreateResourceProps & De
|
|||||||
|
|
||||||
const creatingResources = resources.map(async (resource) => {
|
const creatingResources = resources.map(async (resource) => {
|
||||||
try {
|
try {
|
||||||
const data = await resourceApplierApi.update(resource);
|
const data = await requestKubeObjectCreation(dump(resource));
|
||||||
const { kind, apiVersion, metadata: { name, namespace }} = data;
|
const { kind, apiVersion, metadata: { name, namespace }} = data;
|
||||||
|
|
||||||
const showDetails = () => {
|
const showDetails = () => {
|
||||||
@ -168,5 +170,6 @@ export const CreateResource = withInjectables<Dependencies, CreateResourceProps>
|
|||||||
apiManager: di.inject(apiManagerInjectable),
|
apiManager: di.inject(apiManagerInjectable),
|
||||||
getDetailsUrl: di.inject(getDetailsUrlInjectable),
|
getDetailsUrl: di.inject(getDetailsUrlInjectable),
|
||||||
navigate: di.inject(navigateInjectable),
|
navigate: di.inject(navigateInjectable),
|
||||||
|
requestKubeObjectCreation: di.inject(requestKubeObjectCreationInjectable),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user