Skip to content

Commit

Permalink
Move lookupApi into apiManager
Browse files Browse the repository at this point in the history
- Don't export kube-api-parse from kube-api (cir-deps)

Signed-off-by: Sebastian Malton <[email protected]>
  • Loading branch information
Nokel81 committed Aug 4, 2021
1 parent 574aea4 commit 1f38d62
Show file tree
Hide file tree
Showing 15 changed files with 68 additions and 88 deletions.
42 changes: 41 additions & 1 deletion src/renderer/api/api-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ import type { KubeObjectStore } from "../kube-object.store";

import { action, observable, makeObservable } from "mobx";
import { autoBind, iter } from "../utils";
import { KubeApi, parseKubeApi } from "./kube-api";
import type { KubeApi } from "./kube-api";
import type { KubeObject } from "./kube-object";
import { IKubeObjectRef, parseKubeApi, createKubeApiURL } from "./kube-api-parse";

export class ApiManager {
private apis = observable.map<string, KubeApi<KubeObject>>();
Expand Down Expand Up @@ -91,6 +92,45 @@ export class ApiManager {
getStore<S extends KubeObjectStore<KubeObject>>(api: string | KubeApi<KubeObject>): S | undefined {
return this.stores.get(this.resolveApi(api)?.apiBase) as S;
}

lookupApiLink(ref: IKubeObjectRef, parentObject: KubeObject): string {
const {
kind, apiVersion, name,
namespace = parentObject.getNs()
} = ref;

if (!kind) return "";

// search in registered apis by 'kind' & 'apiVersion'
const api = this.getApi(api => api.kind === kind && api.apiVersionWithGroup == apiVersion);

if (api) {
return api.getUrl({ namespace, name });
}

// lookup api by generated resource link
const apiPrefixes = ["/apis", "/api"];
const resource = kind.endsWith("s") ? `${kind.toLowerCase()}es` : `${kind.toLowerCase()}s`;

for (const apiPrefix of apiPrefixes) {
const apiLink = createKubeApiURL({ apiPrefix, apiVersion, name, namespace, resource });

if (this.getApi(apiLink)) {
return apiLink;
}
}

// resolve by kind only (hpa's might use refs to older versions of resources for example)
const apiByKind = this.getApi(api => api.kind === kind);

if (apiByKind) {
return apiByKind.getUrl({ name, namespace });
}

// otherwise generate link with default prefix
// resource still might exists in k8s, but api is not registered in the app
return createKubeApiURL({ apiVersion, name, namespace, resource });
}
}

export const apiManager = new ApiManager();
20 changes: 3 additions & 17 deletions src/renderer/api/endpoints/resource-applier.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,35 +20,21 @@
*/

import jsYaml from "js-yaml";
import { KubeObject } from "../kube-object";
import type { KubeJsonApiData } from "../kube-json-api";
import { apiBase } from "../index";
import { apiManager } from "../api-manager";

export const resourceApplierApi = {
annotations: [
"kubectl.kubernetes.io/last-applied-configuration"
],

async update<K extends KubeObject>(resource: object | string): Promise<K | null> {
async update(resource: object | string): Promise<KubeJsonApiData | null> {
if (typeof resource === "string") {
resource = jsYaml.safeLoad(resource);
}

return apiBase
.post<KubeJsonApiData[]>("/stack", { data: resource })
.then(data => {
const items = data.map(obj => {
const api = apiManager.getApiByKind(obj.kind, obj.apiVersion);
const [data = null] = await apiBase.post<KubeJsonApiData[]>("/stack", { data: resource });

if (api) {
return new api.objectConstructor(obj);
} else {
return new KubeObject(obj);
}
});

return items[0] as K ?? null;
});
return data;
}
};
41 changes: 0 additions & 41 deletions src/renderer/api/kube-api-parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@

// Parse kube-api path and get api-version, group, etc.

import type { KubeObject } from "./kube-object";
import { splitArray } from "../../common/utils";
import { apiManager } from "./api-manager";
import { isDebugging } from "../../common/vars";
import logger from "../../main/logger";
import { inspect } from "util";
Expand Down Expand Up @@ -159,42 +157,3 @@ export function createKubeApiURL(ref: IKubeApiLinkRef): string {
.filter(v => v)
.join("/");
}

export function lookupApiLink(ref: IKubeObjectRef, parentObject: KubeObject): string {
const {
kind, apiVersion, name,
namespace = parentObject.getNs()
} = ref;

if (!kind) return "";

// search in registered apis by 'kind' & 'apiVersion'
const api = apiManager.getApi(api => api.kind === kind && api.apiVersionWithGroup == apiVersion);

if (api) {
return api.getUrl({ namespace, name });
}

// lookup api by generated resource link
const apiPrefixes = ["/apis", "/api"];
const resource = kind.endsWith("s") ? `${kind.toLowerCase()}es` : `${kind.toLowerCase()}s`;

for (const apiPrefix of apiPrefixes) {
const apiLink = createKubeApiURL({ apiPrefix, apiVersion, name, namespace, resource });

if (apiManager.getApi(apiLink)) {
return apiLink;
}
}

// resolve by kind only (hpa's might use refs to older versions of resources for example)
const apiByKind = apiManager.getApi(api => api.kind === kind);

if (apiByKind) {
return apiByKind.getUrl({ name, namespace });
}

// otherwise generate link with default prefix
// resource still might exists in k8s, but api is not registered in the app
return createKubeApiURL({ apiVersion, name, namespace, resource });
}
7 changes: 0 additions & 7 deletions src/renderer/api/kube-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,6 @@ export interface IKubeApiOptions<T extends KubeObject> {
checkPreferredVersion?: boolean;
}

export interface KubeApiListOptions {
namespace?: string;
reqInit?: RequestInit;
}

export interface IKubeApiQueryParams {
watch?: boolean | number;
resourceVersion?: string;
Expand Down Expand Up @@ -506,5 +501,3 @@ export class KubeApi<T extends KubeObject> {
}
}
}

export * from "./kube-api-parse";
4 changes: 2 additions & 2 deletions src/renderer/api/kube-object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,14 +287,14 @@ export class KubeObject<Metadata extends KubeObjectMetadata = KubeObjectMetadata
}

// use unified resource-applier api for updating all k8s objects
async update<K extends KubeObject>(data: Partial<K>): Promise<K> {
async update(data: Partial<this>): Promise<KubeJsonApiData | null> {
for (const field of KubeObject.nonEditableFields) {
if (!_.isEqual(_.get(this, field), _.get(data, field))) {
throw new Error(`Failed to update Kube Object: ${field} has been modified`);
}
}

return resourceApplierApi.update<K>({
return resourceApplierApi.update({
...this.toPlainObject(),
...data,
});
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/components/+cluster/cluster-issues.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import { boundMethod, cssNames, prevDefault } from "../../utils";
import type { ItemObject } from "../../item.store";
import { Spinner } from "../spinner";
import { ThemeStore } from "../../theme.store";
import { lookupApiLink } from "../../api/kube-api";
import { apiManager } from "../../api/api-manager";
import { kubeSelectedUrlParam, showDetails } from "../kube-detail-params";
import { kubeWatchApi } from "../../api/kube-watch-api";

Expand Down Expand Up @@ -106,7 +106,7 @@ export class ClusterIssues extends React.Component<Props> {
age: getAge(),
message,
kind,
selfLink: lookupApiLink(involvedObject, error),
selfLink: apiManager.lookupApiLink(involvedObject, error),
});
});

Expand Down
6 changes: 3 additions & 3 deletions src/renderer/components/+config-autoscalers/hpa-details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import type { KubeObjectDetailsProps } from "../kube-object-details";
import { cssNames } from "../../utils";
import { HorizontalPodAutoscaler, HpaMetricType, IHpaMetric } from "../../api/endpoints/hpa.api";
import { Table, TableCell, TableHead, TableRow } from "../table";
import { lookupApiLink } from "../../api/kube-api";
import { apiManager } from "../../api/api-manager";
import { KubeObjectMeta } from "../kube-object-meta";
import { getDetailsUrl } from "../kube-detail-params";

Expand All @@ -55,7 +55,7 @@ export class HpaDetails extends React.Component<HpaDetailsProps> {
case HpaMetricType.Object:
const { target } = metric.object;
const { kind, name } = target;
const objectUrl = getDetailsUrl(lookupApiLink(target, hpa));
const objectUrl = getDetailsUrl(apiManager.lookupApiLink(target, hpa));

return (
<>
Expand Down Expand Up @@ -108,7 +108,7 @@ export class HpaDetails extends React.Component<HpaDetailsProps> {

<DrawerItem name="Reference">
{scaleTargetRef && (
<Link to={getDetailsUrl(lookupApiLink(scaleTargetRef, hpa))}>
<Link to={getDetailsUrl(apiManager.lookupApiLink(scaleTargetRef, hpa))}>
{scaleTargetRef.kind}/{scaleTargetRef.name}
</Link>
)}
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/components/+events/event-details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import type { KubeObjectDetailsProps } from "../kube-object-details";
import type { KubeEvent } from "../../api/endpoints/events.api";
import { KubeObjectMeta } from "../kube-object-meta";
import { Table, TableCell, TableHead, TableRow } from "../table";
import { lookupApiLink } from "../../api/kube-api";
import { apiManager } from "../../api/api-manager";
import { LocaleDate } from "../locale-date";
import { getDetailsUrl } from "../kube-detail-params";

Expand Down Expand Up @@ -82,7 +82,7 @@ export class EventDetails extends React.Component<Props> {
</TableHead>
<TableRow>
<TableCell>
<Link to={getDetailsUrl(lookupApiLink(involvedObject, event))}>
<Link to={getDetailsUrl(apiManager.lookupApiLink(involvedObject, event))}>
{name}
</Link>
</TableCell>
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/components/+events/events.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import { Tooltip } from "../tooltip";
import { Link } from "react-router-dom";
import { cssNames, IClassName, stopPropagation } from "../../utils";
import { Icon } from "../icon";
import { lookupApiLink } from "../../api/kube-api";
import { apiManager } from "../../api/api-manager";
import { eventsURL } from "../../../common/routes";
import { getDetailsUrl } from "../kube-detail-params";

Expand Down Expand Up @@ -196,7 +196,7 @@ export class Events extends React.Component<Props> {
)
},
event.getNs(),
<Link key="link" to={getDetailsUrl(lookupApiLink(involvedObject, event))} onClick={stopPropagation}>
<Link key="link" to={getDetailsUrl(apiManager.lookupApiLink(involvedObject, event))} onClick={stopPropagation}>
{involvedObject.kind}: {involvedObject.name}
</Link>,
event.getSource(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { observer } from "mobx-react";
import { EndpointSubset, Endpoint, EndpointAddress} from "../../api/endpoints";
import { Table, TableCell, TableHead, TableRow } from "../table";
import { boundMethod } from "../../utils";
import { lookupApiLink } from "../../api/kube-api";
import { apiManager } from "../../api/api-manager";
import { Link } from "react-router-dom";
import { getDetailsUrl } from "../kube-detail-params";

Expand Down Expand Up @@ -92,7 +92,7 @@ export class EndpointSubsetList extends React.Component<Props> {
<TableCell className="name">{address.hostname}</TableCell>
<TableCell className="target">
{ address.targetRef && (
<Link to={getDetailsUrl(lookupApiLink(address.getTargetRef(), endpoint))}>
<Link to={getDetailsUrl(apiManager.lookupApiLink(address.getTargetRef(), endpoint))}>
{address.targetRef.name}
</Link>
)}
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/components/+workloads-jobs/job-details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import { jobStore } from "./job.store";
import type { KubeObjectDetailsProps } from "../kube-object-details";
import { getMetricsForJobs, IPodMetrics, Job } from "../../api/endpoints";
import { PodDetailsList } from "../+workloads-pods/pod-details-list";
import { lookupApiLink } from "../../api/kube-api";
import { apiManager } from "../../api/api-manager";
import { KubeObjectMeta } from "../kube-object-meta";
import { makeObservable, observable } from "mobx";
import { podMetricTabs, PodCharts } from "../+workloads-pods/pod-charts";
Expand Down Expand Up @@ -117,7 +117,7 @@ export class JobDetails extends React.Component<Props> {
{
ownerRefs.map(ref => {
const { name, kind } = ref;
const detailsUrl = getDetailsUrl(lookupApiLink(ref, job));
const detailsUrl = getDetailsUrl(apiManager.lookupApiLink(ref, job));

return (
<p key={name}>
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/components/+workloads-pods/pods.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import { cssNames, stopPropagation } from "../../utils";
import toPairs from "lodash/toPairs";
import startCase from "lodash/startCase";
import kebabCase from "lodash/kebabCase";
import { lookupApiLink } from "../../api/kube-api";
import { apiManager } from "../../api/api-manager";
import { KubeObjectStatusIcon } from "../kube-object-status-icon";
import { Badge } from "../badge";
import type { PodsRouteParams } from "../../../common/routes";
Expand Down Expand Up @@ -135,7 +135,7 @@ export class Pods extends React.Component<Props> {
pod.getRestartsCount(),
pod.getOwnerRefs().map(ref => {
const { kind, name } = ref;
const detailsLink = getDetailsUrl(lookupApiLink(ref, pod));
const detailsLink = getDetailsUrl(apiManager.lookupApiLink(ref, pod));

return (
<Badge flat key={name} className="owner" tooltip={name}>
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/components/dock/create-resource.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export class CreateResource extends React.Component<Props> {
await Promise.all(
resources.map(data => {
return resourceApplierApi.update(data)
.then(item => createdResources.push(item.getName()))
.then(item => createdResources.push(item.metadata.name))
.catch((err: JsonApiErrorParsed) => errors.push(err.toString()));
})
);
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/components/kube-object-meta/kube-object-meta.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import React from "react";
import type { KubeMetaField, KubeObject } from "../../api/kube-object";
import { DrawerItem, DrawerItemLabels } from "../drawer";
import { lookupApiLink } from "../../api/kube-api";
import { apiManager } from "../../api/api-manager";
import { Link } from "react-router-dom";
import { KubeObjectStatusIcon } from "../kube-object-status-icon";
import { LocaleDate } from "../locale-date";
Expand Down Expand Up @@ -93,7 +93,7 @@ export class KubeObjectMeta extends React.Component<KubeObjectMetaProps> {
{
ownerRefs.map(ref => {
const { name, kind } = ref;
const ownerDetailsUrl = getDetailsUrl(lookupApiLink(ref, object));
const ownerDetailsUrl = getDetailsUrl(apiManager.lookupApiLink(ref, object));

return (
<p key={name}>
Expand Down
6 changes: 4 additions & 2 deletions src/renderer/kube-object.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ import { KubeObject, KubeStatus } from "./api/kube-object";
import type { IKubeWatchEvent } from "./api/kube-watch-api";
import { ItemStore } from "./item.store";
import { apiManager } from "./api/api-manager";
import { ensureObjectSelfLink, IKubeApiQueryParams, KubeApi, parseKubeApi } from "./api/kube-api";
import { ensureObjectSelfLink, IKubeApiQueryParams, KubeApi } from "./api/kube-api";
import { parseKubeApi } from "./api/kube-api-parse";
import type { KubeJsonApiData } from "./api/kube-json-api";
import { Notifications } from "./components/notifications";

Expand Down Expand Up @@ -279,7 +280,8 @@ export abstract class KubeObjectStore<T extends KubeObject> extends ItemStore<T>
}

async update(item: T, data: Partial<T>): Promise<T> {
const newItem = await item.update(data);
const rawItem = await item.update(data);
const newItem = new this.api.objectConstructor(rawItem);

ensureObjectSelfLink(this.api, newItem);

Expand Down

0 comments on commit 1f38d62

Please sign in to comment.