cleanup Lens repo with tighter linting

Signed-off-by: Sebastian Malton <smalton@mirantis.com>
This commit is contained in:
Sebastian Malton committed 2020-07-09 17:00:23 -04:00
1 parent e468105143
commit b1ff34879a
470 files changed
+8447 -7443

No files matched your search

@@ -18,7 +18,7 @@ const cronJob = new CronJob({
suspend: false,
},
status: {}
} as any)
} as any);
describe("Check for CronJob schedule never run", () => {
test("Should be false with normal schedule", () => {
@@ -31,12 +31,12 @@ describe("Check for CronJob schedule never run", () => {
});
test("Should be true with date 31 of February", () => {
cronJob.spec.schedule = "30 06 31 2 *"
cronJob.spec.schedule = "30 06 31 2 *";
expect(cronJob.isNeverRun()).toBeTruthy();
});
test("Should be true with date 32 of July", () => {
cronJob.spec.schedule = "0 30 06 32 7 *"
cronJob.spec.schedule = "0 30 06 32 7 *";
expect(cronJob.isNeverRun()).toBeTruthy();
});
+150 -120
View File
@@ -3,96 +3,23 @@
// API docs: https://docs.cert-manager.io/en/latest/reference/api-docs/index.html
import { KubeObject } from "../kube-object";
import { ISecretRef, secretsApi } from "./secret.api";
import { SecretRef, secretsApi } from "./secret.api";
import { getDetailsUrl } from "../../navigation";
import { KubeApi } from "../kube-api";
export class Certificate extends KubeObject {
static kind = "Certificate"
export type IssuerType = "ACME" | "CA" | "SelfSigned" | "Vault" | "Venafi";
spec: {
secretName: string;
commonName?: string;
dnsNames?: string[];
organization?: string[];
ipAddresses?: string[];
duration?: string;
renewBefore?: string;
isCA?: boolean;
keySize?: number;
keyAlgorithm?: "rsa" | "ecdsa";
issuerRef: {
kind?: string;
name: string;
};
acme?: {
config: {
domains: string[];
http01: {
ingress?: string;
ingressClass?: string;
};
dns01?: {
provider: string;
};
}[];
};
}
status: {
conditions?: {
lastTransitionTime: string; // 2019-06-04T07:35:58Z,
message: string; // Certificate is up to date and has not expired,
reason: string; // Ready,
status: string; // True,
type: string; // Ready
}[];
notAfter: string; // 2019-11-01T05:36:27Z
lastFailureTime?: string;
}
export interface IssuerConditionBase {
lastTransitionTime: string; // 2019-06-05T07:10:42Z,
message: string; // The ACME account was registered with the ACME server,
reason: string; // ACMEAccountRegistered,
status: string; // True,
type: string; // Ready
}
getType(): string {
const { isCA, acme } = this.spec;
if (isCA) return "CA"
if (acme) return "ACME"
}
getCommonName() {
return this.spec.commonName || ""
}
getIssuerName() {
return this.spec.issuerRef.name;
}
getSecretName() {
return this.spec.secretName;
}
getIssuerDetailsUrl() {
return getDetailsUrl(issuersApi.getUrl({
namespace: this.getNs(),
name: this.getIssuerName(),
}))
}
getSecretDetailsUrl() {
return getDetailsUrl(secretsApi.getUrl({
namespace: this.getNs(),
name: this.getSecretName(),
}))
}
getConditions() {
const { conditions = [] } = this.status;
return conditions.map(condition => {
const { message, reason, lastTransitionTime, status } = condition;
return {
...condition,
isReady: status === "True",
tooltip: `${message || reason} (${lastTransitionTime})`
}
});
}
export interface IssuerCondition extends IssuerConditionBase {
tooltip: string;
isReady: boolean;
}
export class Issuer extends KubeObject {
@@ -103,23 +30,23 @@ export class Issuer extends KubeObject {
email: string;
server: string;
skipTLSVerify?: boolean;
privateKeySecretRef: ISecretRef;
privateKeySecretRef: SecretRef;
solvers?: {
dns01?: {
cnameStrategy: string;
acmedns?: {
host: string;
accountSecretRef: ISecretRef;
accountSecretRef: SecretRef;
};
akamai?: {
accessTokenSecretRef: ISecretRef;
clientSecretSecretRef: ISecretRef;
clientTokenSecretRef: ISecretRef;
accessTokenSecretRef: SecretRef;
clientSecretSecretRef: SecretRef;
clientTokenSecretRef: SecretRef;
serviceConsumerDomain: string;
};
azuredns?: {
clientID: string;
clientSecretSecretRef: ISecretRef;
clientSecretSecretRef: SecretRef;
hostedZoneName: string;
resourceGroupName: string;
subscriptionID: string;
@@ -127,26 +54,26 @@ export class Issuer extends KubeObject {
};
clouddns?: {
project: string;
serviceAccountSecretRef: ISecretRef;
serviceAccountSecretRef: SecretRef;
};
cloudflare?: {
email: string;
apiKeySecretRef: ISecretRef;
apiKeySecretRef: SecretRef;
};
digitalocean?: {
tokenSecretRef: ISecretRef;
tokenSecretRef: SecretRef;
};
rfc2136?: {
nameserver: string;
tsigAlgorithm: string;
tsigKeyName: string;
tsigSecretSecretRef: ISecretRef;
tsigSecretSecretRef: SecretRef;
};
route53?: {
accessKeyID: string;
hostedZoneID: string;
region: string;
secretAccessKeySecretRef: ISecretRef;
secretAccessKeySecretRef: SecretRef;
};
webhook?: {
config: object; // arbitrary json
@@ -180,7 +107,7 @@ export class Issuer extends KubeObject {
appRole: {
path: string;
roleId: string;
secretRef: ISecretRef;
secretRef: SecretRef;
};
};
};
@@ -188,7 +115,7 @@ export class Issuer extends KubeObject {
venafi?: {
zone: string;
cloud?: {
apiTokenSecretRef: ISecretRef;
apiTokenSecretRef: SecretRef;
};
tpp?: {
url: string;
@@ -204,25 +131,29 @@ export class Issuer extends KubeObject {
acme?: {
uri: string;
};
conditions?: {
lastTransitionTime: string; // 2019-06-05T07:10:42Z,
message: string; // The ACME account was registered with the ACME server,
reason: string; // ACMEAccountRegistered,
status: string; // True,
type: string; // Ready
}[];
conditions?: IssuerConditionBase[];
}
getType() {
getType(): IssuerType {
const { acme, ca, selfSigned, vault, venafi } = this.spec;
if (acme) return "ACME"
if (ca) return "CA"
if (selfSigned) return "SelfSigned"
if (vault) return "Vault"
if (venafi) return "Venafi"
if (acme) {
return "ACME";
}
if (ca) {
return "CA";
}
if (selfSigned) {
return "SelfSigned";
}
if (vault) {
return "Vault";
}
if (venafi) {
return "Venafi";
}
}
getConditions() {
getConditions(): IssuerCondition[] {
const { conditions = [] } = this.status;
return conditions.map(condition => {
const { message, reason, lastTransitionTime, status } = condition;
@@ -230,7 +161,113 @@ export class Issuer extends KubeObject {
...condition,
isReady: status === "True",
tooltip: `${message || reason} (${lastTransitionTime})`,
}
};
});
}
}
export const issuersApi = new KubeApi({
kind: Issuer.kind,
apiBase: "/apis/cert-manager.io/v1alpha2/issuers",
isNamespaced: true,
objectConstructor: Issuer,
});
export interface CertificateConditionBase {
lastTransitionTime: string; // 2019-06-04T07:35:58Z,
message: string; // Certificate is up to date and has not expired,
reason: string; // Ready,
status: string; // True,
type: string; // Ready
}
export interface CertificateCondition extends CertificateConditionBase {
isReady: boolean;
tooltip: string;
}
export class Certificate extends KubeObject {
static kind = "Certificate"
spec: {
secretName: string;
commonName?: string;
dnsNames?: string[];
organization?: string[];
ipAddresses?: string[];
duration?: string;
renewBefore?: string;
isCA?: boolean;
keySize?: number;
keyAlgorithm?: "rsa" | "ecdsa";
issuerRef: {
kind?: string;
name: string;
};
acme?: {
config: {
domains: string[];
http01: {
ingress?: string;
ingressClass?: string;
};
dns01?: {
provider: string;
};
}[];
};
}
status: {
conditions?: CertificateConditionBase[];
notAfter: string; // 2019-11-01T05:36:27Z
lastFailureTime?: string;
}
getType(): string {
const { isCA, acme } = this.spec;
if (isCA) {
return "CA";
}
if (acme) {
return "ACME";
}
}
getCommonName(): string {
return this.spec.commonName || "";
}
getIssuerName(): string {
return this.spec.issuerRef.name;
}
getSecretName(): string {
return this.spec.secretName;
}
getIssuerDetailsUrl(): string {
return getDetailsUrl(issuersApi.getUrl({
namespace: this.getNs(),
name: this.getIssuerName(),
}));
}
getSecretDetailsUrl(): string {
return getDetailsUrl(secretsApi.getUrl({
namespace: this.getNs(),
name: this.getSecretName(),
}));
}
getConditions(): CertificateCondition[] {
const { conditions = [] } = this.status;
return conditions.map(condition => {
const { message, reason, lastTransitionTime, status } = condition;
return {
...condition,
isReady: status === "True",
tooltip: `${message || reason} (${lastTransitionTime})`
};
});
}
}
@@ -246,13 +283,6 @@ export const certificatesApi = new KubeApi({
objectConstructor: Certificate,
});
export const issuersApi = new KubeApi({
kind: Issuer.kind,
apiBase: "/apis/cert-manager.io/v1alpha2/issuers",
isNamespaced: true,
objectConstructor: Issuer,
});
export const clusterIssuersApi = new KubeApi({
kind: ClusterIssuer.kind,
apiBase: "/apis/cert-manager.io/v1alpha2/clusterissuers",
+14 -8
View File
@@ -1,11 +1,11 @@
import { IMetrics, IMetricsReqParams, metricsApi } from "./metrics.api";
import { Metrics, MetricsReqParams, metricsApi } from "./metrics.api";
import { KubeObject } from "../kube-object";
import { KubeApi } from "../kube-api";
export class ClusterApi extends KubeApi<Cluster> {
async getMetrics(nodeNames: string[], params?: IMetricsReqParams): Promise<IClusterMetrics> {
async getMetrics(nodeNames: string[], params?: MetricsReqParams): Promise<ClusterMetrics> {
const nodes = nodeNames.join("|");
const opts = { category: "cluster", nodes: nodes }
const opts = { category: "cluster", nodes: nodes };
return metricsApi.getMetrics({
memoryUsage: opts,
@@ -31,7 +31,7 @@ export enum ClusterStatus {
ERROR = "Error"
}
export interface IClusterMetrics<T = IMetrics> {
export interface ClusterMetrics<T = Metrics> {
[metric: string]: T;
memoryUsage: T;
memoryRequests: T;
@@ -82,10 +82,16 @@ export class Cluster extends KubeObject {
errorReason?: string;
}
getStatus() {
if (this.metadata.deletionTimestamp) return ClusterStatus.REMOVING;
if (!this.status || !this.status) return ClusterStatus.CREATING;
if (this.status.errorMessage) return ClusterStatus.ERROR;
getStatus(): ClusterStatus {
if (this.metadata.deletionTimestamp) {
return ClusterStatus.REMOVING;
}
if (!this.status || !this.status) {
return ClusterStatus.CREATING;
}
if (this.status.errorMessage) {
return ClusterStatus.ERROR;
}
return ClusterStatus.ACTIVE;
}
}
@@ -1,7 +1,7 @@
import { KubeObject } from "../kube-object";
import { KubeApi } from "../kube-api";
export interface IComponentStatusCondition {
export interface ComponentStatusCondition {
type: string;
status: string;
message: string;
@@ -10,9 +10,9 @@ export interface IComponentStatusCondition {
export class ComponentStatus extends KubeObject {
static kind = "ComponentStatus"
conditions: IComponentStatusCondition[]
conditions: ComponentStatusCondition[]
getTruthyConditions() {
getTruthyConditions(): ComponentStatusCondition[] {
return this.conditions.filter(c => c.status === "True");
}
}
+3 -2
View File
@@ -1,9 +1,10 @@
// App configuration api
import { apiBase } from "../index";
import { IConfig } from "../../../server/common/config";
import { CancelablePromise } from "client/utils/cancelableFetch";
export const configApi = {
getConfig() {
return apiBase.get<IConfig>("/config")
getConfig(): CancelablePromise<IConfig> {
return apiBase.get<IConfig>("/config");
},
};
+22 -23
View File
@@ -51,81 +51,80 @@ export class CustomResourceDefinition extends KubeObject {
storedVersions: string[];
}
getResourceUrl() {
getResourceUrl(): string {
return crdResourcesURL({
params: {
group: this.getGroup(),
name: this.getPluralName(),
}
})
});
}
getResourceApiBase() {
getResourceApiBase(): string {
const { version, group } = this.spec;
return `/apis/${group}/${version}/${this.getPluralName()}`
return `/apis/${group}/${version}/${this.getPluralName()}`;
}
getPluralName() {
return this.getNames().plural
getPluralName(): string {
return this.getNames().plural;
}
getResourceKind() {
return this.spec.names.kind
getResourceKind(): string {
return this.spec.names.kind;
}
getResourceTitle() {
getResourceTitle(): string {
const name = this.getPluralName();
return name[0].toUpperCase() + name.substr(1)
return name[0].toUpperCase() + name.substr(1);
}
getGroup() {
getGroup(): string {
return this.spec.group;
}
getScope() {
getScope(): string {
return this.spec.scope;
}
getVersion() {
getVersion(): string {
return this.spec.version;
}
isNamespaced() {
isNamespaced(): boolean {
return this.getScope() === "Namespaced";
}
getStoredVersions() {
getStoredVersions(): string {
return this.status.storedVersions.join(", ");
}
getNames() {
getNames(): CustomResourceDefinition["spec"]["names"] {
return this.spec.names;
}
getConversion() {
getConversion(): string {
return JSON.stringify(this.spec.conversion);
}
getPrinterColumns(ignorePriority = true) {
getPrinterColumns(ignorePriority = true): Required<CustomResourceDefinition["spec"]["additionalPrinterColumns"]> {
const columns = this.spec.additionalPrinterColumns || [];
return columns
.filter(column => column.name != "Age")
.filter(column => ignorePriority ? true : !column.priority);
}
getValidation() {
getValidation(): string {
return JSON.stringify(this.spec.validation, null, 2);
}
getConditions() {
if (!this.status.conditions) return [];
return this.status.conditions.map(condition => {
getConditions(): Required<CustomResourceDefinition["status"]["conditions"]> {
return (this.status.conditions || []).map(condition => {
const { message, reason, lastTransitionTime, status } = condition;
return {
...condition,
isReady: status === "True",
tooltip: `${message || reason} (${lastTransitionTime})`
}
};
});
}
}
+12 -11
View File
@@ -1,6 +1,6 @@
import moment from "moment";
import { KubeObject } from "../kube-object";
import { IPodContainer } from "./pods.api";
import { PodContainer } from "./pods.api";
import { formatDuration } from "../../utils/formatDuration";
import { autobind } from "../../utils";
import { KubeApi } from "../kube-api";
@@ -39,7 +39,7 @@ export class CronJob extends KubeObject {
creationTimestamp?: string;
};
spec: {
containers: IPodContainer[];
containers: PodContainer[];
restartPolicy: string;
terminationGracePeriodSeconds: number;
dnsPolicy: string;
@@ -56,26 +56,27 @@ export class CronJob extends KubeObject {
lastScheduleTime: string;
}
getSuspendFlag() {
return this.spec.suspend.toString()
getSuspendFlag(): string {
return this.spec.suspend.toString();
}
getLastScheduleTime() {
const diff = moment().diff(this.status.lastScheduleTime)
return formatDuration(diff, true)
getLastScheduleTime(): string {
return formatDuration(moment().diff(this.status.lastScheduleTime), true);
}
getSchedule() {
return this.spec.schedule
getSchedule(): string {
return this.spec.schedule;
}
isNeverRun() {
isNeverRun(): boolean {
const schedule = this.getSchedule();
const daysInMonth = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
const stamps = schedule.split(" ");
const day = Number(stamps[stamps.length - 3]); // 1-31
const month = Number(stamps[stamps.length - 2]); // 1-12
if (schedule.startsWith("@")) return false;
if (schedule.startsWith("@")) {
return false;
}
return day > daysInMonth[month - 1];
}
}
@@ -1,6 +1,6 @@
import get from "lodash/get";
import { IPodContainer } from "./pods.api";
import { IAffinity, WorkloadKubeObject } from "../workload-kube-object";
import { PodContainer } from "./pods.api";
import { Affinity, WorkloadKubeObject } from "../workload-kube-object";
import { autobind } from "../../utils";
import { KubeApi } from "../kube-api";
@@ -22,13 +22,13 @@ export class DaemonSet extends WorkloadKubeObject {
};
};
spec: {
containers: IPodContainer[];
initContainers?: IPodContainer[];
containers: PodContainer[];
initContainers?: PodContainer[];
restartPolicy: string;
terminationGracePeriodSeconds: number;
dnsPolicy: string;
hostPID: boolean;
affinity?: IAffinity;
affinity?: Affinity;
nodeSelector?: {
[selector: string]: string;
};
@@ -61,10 +61,10 @@ export class DaemonSet extends WorkloadKubeObject {
numberUnavailable: number;
}
getImages() {
const containers: IPodContainer[] = get(this, "spec.template.spec.containers", [])
const initContainers: IPodContainer[] = get(this, "spec.template.spec.initContainers", [])
return [...containers, ...initContainers].map(container => container.image)
getImages(): string[] {
const containers: PodContainer[] = get(this, "spec.template.spec.containers", []);
const initContainers: PodContainer[] = get(this, "spec.template.spec.initContainers", []);
return [...containers, ...initContainers].map(container => container.image);
}
}
@@ -1,27 +1,24 @@
import { IAffinity, WorkloadKubeObject } from "../workload-kube-object";
import { Affinity, WorkloadKubeObject } from "../workload-kube-object";
import { autobind } from "../../utils";
import { KubeApi } from "../kube-api";
import { CancelablePromise } from "client/utils/cancelableFetch";
import { KubeJsonApiData } from "../kube-json-api";
export class DeploymentApi extends KubeApi<Deployment> {
protected getScaleApiUrl(params: { namespace: string; name: string }) {
return this.getUrl(params) + "/scale"
protected getScaleApiUrl(params: { namespace: string; name: string }): string {
return this.getUrl(params) + "/scale";
}
getReplicas(params: { namespace: string; name: string }): Promise<number> {
return this.request
.get(this.getScaleApiUrl(params))
.then(({ status }: any) => status.replicas)
async getReplicas(params: { namespace: string; name: string }): Promise<number> {
const { status } = await this.request.get(this.getScaleApiUrl(params));
return status.replicas;
}
scale(params: { namespace: string; name: string }, replicas: number) {
return this.request.put(this.getScaleApiUrl(params), {
data: {
metadata: params,
spec: {
replicas: replicas
}
}
})
scale(metadata: { namespace: string; name: string }, replicas: number): CancelablePromise<KubeJsonApiData> {
return this.request.put(
this.getScaleApiUrl(metadata),
{ data: { metadata, spec: { replicas } } }
);
}
}
@@ -96,7 +93,7 @@ export class Deployment extends WorkloadKubeObject {
restartPolicy: string;
terminationGracePeriodSeconds: number;
dnsPolicy: string;
affinity?: IAffinity;
affinity?: Affinity;
nodeSelector?: {
[selector: string]: string;
};
@@ -145,20 +142,15 @@ export class Deployment extends WorkloadKubeObject {
}[];
}
getConditions(activeOnly = false) {
const { conditions } = this.status
if (!conditions) return []
if (activeOnly) {
return conditions.filter(c => c.status === "True")
}
return conditions
getConditions(activeOnly = false): Deployment["status"]["conditions"] {
return this.status.conditions.filter(({ status }) => !activeOnly || status === "True");
}
getConditionsText(activeOnly = true) {
return this.getConditions(activeOnly).map(({ type }) => type).join(" ")
getConditionsText(activeOnly = true): string {
return this.getConditions(activeOnly).map(({ type }) => type).join(" ");
}
getReplicas() {
getReplicas(): number {
return this.spec.replicas || 0;
}
}
+31 -31
View File
@@ -2,25 +2,25 @@ import { autobind } from "../../utils";
import { KubeObject } from "../kube-object";
import { KubeApi } from "../kube-api";
export interface IEndpointPort {
export interface EndpointPort {
name?: string;
protocol: string;
port: number;
}
export interface IEndpointAddress {
export interface EndpointAddress {
hostname: string;
ip: string;
nodeName: string;
}
export interface IEndpointSubset {
addresses: IEndpointAddress[];
notReadyAddresses: IEndpointAddress[];
ports: IEndpointPort[];
export interface EndpointSubset {
addresses: EndpointAddress[];
notReadyAddresses: EndpointAddress[];
ports: EndpointPort[];
}
interface ITargetRef {
interface TargetRef {
kind: string;
namespace: string;
name: string;
@@ -29,7 +29,7 @@ interface ITargetRef {
apiVersion: string;
}
export class EndpointAddress implements IEndpointAddress {
export class EndpointAddress implements EndpointAddress {
hostname: string;
ip: string;
nodeName: string;
@@ -41,34 +41,34 @@ export class EndpointAddress implements IEndpointAddress {
resourceVersion: string;
};
constructor(data: IEndpointAddress) {
Object.assign(this, data)
constructor(data: EndpointAddress) {
Object.assign(this, data);
}
getId() {
return this.ip
getId(): string {
return this.ip;
}
getName() {
return this.hostname
getName(): string {
return this.hostname;
}
getTargetRef(): ITargetRef {
getTargetRef(): TargetRef {
if (this.targetRef) {
return Object.assign(this.targetRef, {apiVersion: "v1"})
return Object.assign(this.targetRef, {apiVersion: "v1"});
} else {
return null
return null;
}
}
}
export class EndpointSubset implements IEndpointSubset {
addresses: IEndpointAddress[];
notReadyAddresses: IEndpointAddress[];
ports: IEndpointPort[];
export class EndpointSubset implements EndpointSubset {
addresses: EndpointAddress[];
notReadyAddresses: EndpointAddress[];
ports: EndpointPort[];
constructor(data: IEndpointSubset) {
Object.assign(this, data)
constructor(data: EndpointSubset) {
Object.assign(this, data);
}
getAddresses(): EndpointAddress[] {
@@ -83,16 +83,16 @@ export class EndpointSubset implements IEndpointSubset {
toString(): string {
if(!this.addresses) {
return ""
return "";
}
return this.addresses.map(address => {
if (!this.ports) {
return address.ip
return address.ip;
}
return this.ports.map(port => {
return `${address.ip}:${port.port}`
}).join(", ")
}).join(", ")
return `${address.ip}:${port.port}`;
}).join(", ");
}).join(", ");
}
}
@@ -100,7 +100,7 @@ export class EndpointSubset implements IEndpointSubset {
export class Endpoint extends KubeObject {
static kind = "Endpoint"
subsets: IEndpointSubset[]
subsets: EndpointSubset[]
getEndpointSubsets(): EndpointSubset[] {
const subsets = this.subsets || [];
@@ -109,9 +109,9 @@ export class Endpoint extends KubeObject {
toString(): string {
if(this.subsets) {
return this.getEndpointSubsets().map(es => es.toString()).join(", ")
return this.getEndpointSubsets().map(es => es.toString()).join(", ");
} else {
return "<none>"
return "<none>";
}
}
+11 -11
View File
@@ -31,23 +31,23 @@ export class KubeEvent extends KubeObject {
reportingComponent: string
reportingInstance: string
isWarning() {
isWarning(): boolean {
return this.type === "Warning";
}
getSource() {
const { component, host } = this.source
return `${component} ${host || ""}`
getSource(): string {
const { component, host } = this.source;
return `${component} ${host || ""}`;
}
getFirstSeenTime() {
const diff = moment().diff(this.firstTimestamp)
return formatDuration(diff, true)
getFirstSeenTime(): string {
const diff = moment().diff(this.firstTimestamp);
return formatDuration(diff, true);
}
getLastSeenTime() {
const diff = moment().diff(this.lastTimestamp)
return formatDuration(diff, true)
getLastSeenTime(): string {
const diff = moment().diff(this.lastTimestamp);
return formatDuration(diff, true);
}
}
@@ -56,4 +56,4 @@ export const eventApi = new KubeApi({
apiBase: "/api/v1/events",
isNamespaced: true,
objectConstructor: KubeEvent,
})
});
@@ -2,54 +2,7 @@ import pathToRegExp from "path-to-regexp";
import { apiKubeHelm } from "../index";
import { stringify } from "querystring";
import { autobind } from "../../utils";
interface IHelmChartList {
[repo: string]: {
[name: string]: HelmChart;
};
}
export interface IHelmChartDetails {
readme: string;
versions: HelmChart[];
}
const endpoint = pathToRegExp.compile(`/v2/charts/:repo?/:name?`) as (params?: {
repo?: string;
name?: string;
}) => string;
export const helmChartsApi = {
list() {
return apiKubeHelm
.get<IHelmChartList>(endpoint())
.then(data => {
return Object
.values(data)
.reduce((allCharts, repoCharts) => allCharts.concat(Object.values(repoCharts)), [])
.map(HelmChart.create);
});
},
get(repo: string, name: string, readmeVersion?: string) {
const path = endpoint({ repo, name });
return apiKubeHelm
.get<IHelmChartDetails>(path + "?" + stringify({ version: readmeVersion }))
.then(data => {
const versions = data.versions.map(HelmChart.create);
const readme = data.readme;
return {
readme,
versions,
}
});
},
getValues(repo: string, name: string, version: string) {
return apiKubeHelm
.get<string>(`/v2/charts/${repo}/${name}/values?` + stringify({ version }));
}
};
import { CancelablePromise } from "client/utils/cancelableFetch";
@autobind()
export class HelmChart {
@@ -57,10 +10,6 @@ export class HelmChart {
Object.assign(this, data);
}
static create(data: any) {
return new HelmChart(data);
}
apiVersion: string
name: string
version: string
@@ -83,47 +32,74 @@ export class HelmChart {
deprecated?: boolean
tillerVersion?: string
getId() {
getId(): string {
return this.digest;
}
getName() {
getName(): string {
return this.name;
}
getFullName(splitter = "/") {
return [this.getRepository(), this.getName()].join(splitter);
getFullName(splitter = "/"): string {
return [this.repo, this.name].join(splitter);
}
getDescription() {
return this.description;
}
getIcon() {
return this.icon;
}
getHome() {
return this.home;
}
getMaintainers() {
getMaintainers(): Required<HelmChart["maintainers"]> {
return this.maintainers || [];
}
getVersion() {
return this.version;
}
getRepository() {
return this.repo;
}
getAppVersion() {
getAppVersion(): string {
return this.appVersion || "";
}
getKeywords() {
getKeywords(): Required<HelmChart["keywords"]> {
return this.keywords || [];
}
}
interface HelmChartList {
[repo: string]: {
[name: string]: HelmChart;
};
}
export interface HelmChartDetails {
readme: string;
versions: HelmChart[];
}
const endpoint = pathToRegExp.compile(`/v2/charts/:repo?/:name?`) as (params?: {
repo?: string;
name?: string;
}) => string;
export interface HelmChartInfo {
readme: string;
versions: HelmChart[];
}
export const helmChartsApi = {
list(): CancelablePromise<HelmChart[]> {
return apiKubeHelm.get<HelmChartList>(endpoint())
.then(data => {
return Object.values(data)
.reduce((allCharts, repoCharts) => allCharts.concat(Object.values(repoCharts)), [])
.map(data => new HelmChart(data));
});
},
get(repo: string, name: string, readmeVersion?: string): CancelablePromise<HelmChartInfo> {
const path = endpoint({ repo, name });
return apiKubeHelm.get<HelmChartDetails>(path + "?" + stringify({ version: readmeVersion }))
.then(({ readme, versions }) => ({
readme,
versions: versions.map(data => new HelmChart(data))
}));
},
getValues(repo: string, name: string, version: string): CancelablePromise<string> {
return apiKubeHelm
.get<string>(`/v2/charts/${repo}/${name}/values?` + stringify({ version }));
}
};
@@ -6,8 +6,10 @@ import { apiKubeHelm } from "../index";
import { helmChartStore } from "../../components/+apps-helm-charts/helm-chart.store";
import { ItemObject } from "../../item.store";
import { KubeObject } from "../kube-object";
import { CancelablePromise } from "client/utils/cancelableFetch";
import { KubeJsonApiData } from "../kube-json-api";
interface IReleasePayload {
interface ReleasePayload {
name: string;
namespace: string;
version: string;
@@ -23,15 +25,15 @@ interface IReleasePayload {
};
}
interface IReleaseRawDetails extends IReleasePayload {
interface ReleaseRawDetails extends ReleasePayload {
resources: string;
}
export interface IReleaseDetails extends IReleasePayload {
export interface ReleaseInfo extends ReleasePayload {
resources: KubeObject[];
}
export interface IReleaseCreatePayload {
export interface ReleaseCreatePayload {
name?: string;
repo: string;
chart: string;
@@ -40,19 +42,19 @@ export interface IReleaseCreatePayload {
values: string;
}
export interface IReleaseUpdatePayload {
export interface ReleaseUpdatePayload {
repo: string;
chart: string;
version: string;
values: string;
}
export interface IReleaseUpdateDetails {
export interface ReleaseUpdateDetails {
log: string;
release: IReleaseDetails;
release: ReleaseInfo;
}
export interface IReleaseRevision {
export interface ReleaseRevision {
revision: number;
updated: string;
status: string;
@@ -67,74 +69,12 @@ const endpoint = pathToRegExp.compile(`/v2/releases/:namespace?/:name?`) as (
}
) => string;
export const helmReleasesApi = {
list(namespace?: string) {
return apiKubeHelm
.get<HelmRelease[]>(endpoint({ namespace }))
.then(releases => releases.map(HelmRelease.create));
},
get(name: string, namespace: string) {
const path = endpoint({ name, namespace });
return apiKubeHelm.get<IReleaseRawDetails>(path).then(details => {
const items: KubeObject[] = JSON.parse(details.resources).items;
const resources = items.map(item => KubeObject.create(item));
return {
...details,
resources
}
});
},
create(payload: IReleaseCreatePayload): Promise<IReleaseUpdateDetails> {
const { repo, ...data } = payload;
data.chart = `${repo}/${data.chart}`;
data.values = jsYaml.safeLoad(data.values);
return apiKubeHelm.post(endpoint(), { data });
},
update(name: string, namespace: string, payload: IReleaseUpdatePayload): Promise<IReleaseUpdateDetails> {
const { repo, ...data } = payload;
data.chart = `${repo}/${data.chart}`;
data.values = jsYaml.safeLoad(data.values);
return apiKubeHelm.put(endpoint({ name, namespace }), { data });
},
async delete(name: string, namespace: string) {
const path = endpoint({ name, namespace });
return apiKubeHelm.del(path);
},
getValues(name: string, namespace: string) {
const path = endpoint({ name, namespace }) + "/values";
return apiKubeHelm.get<string>(path);
},
getHistory(name: string, namespace: string): Promise<IReleaseRevision[]> {
const path = endpoint({ name, namespace }) + "/history";
return apiKubeHelm.get(path);
},
rollback(name: string, namespace: string, revision: number) {
const path = endpoint({ name, namespace }) + "/rollback";
return apiKubeHelm.put(path, {
data: {
revision: revision
}
});
}
};
@autobind()
export class HelmRelease implements ItemObject {
constructor(data: any) {
Object.assign(this, data);
}
static create(data: any) {
return new HelmRelease(data);
}
appVersion: string
name: string
namespace: string
@@ -143,45 +83,32 @@ export class HelmRelease implements ItemObject {
updated: string
revision: number
getId() {
getId(): string {
return this.namespace + this.name;
}
getName() {
getName(): string {
return this.name;
}
getNs() {
return this.namespace;
}
getChart(withVersion = false) {
let chart = this.chart
if(!withVersion && this.getVersion() != "" ) {
const search = new RegExp(`-${this.getVersion()}`)
getChart(withVersion = false): string {
let chart = this.chart;
if (!withVersion && this.getVersion() != "") {
const search = new RegExp(`-${this.getVersion()}`);
chart = chart.replace(search, "");
}
return chart
return chart;
}
getRevision() {
return this.revision;
}
getStatus() {
getStatus(): string {
return capitalize(this.status);
}
getVersion() {
const versions = this.chart.match(/(v?\d+)[^-].*$/)
if (versions) {
return versions[0]
} else {
return ""
}
getVersion(): string {
return this.chart.match(/(v?\d+)[^-].*$/)?.[0] || "";
}
getUpdated(humanize = true, compact = true) {
getUpdated(humanize = true, compact = true): number | string {
const now = new Date().getTime();
const updated = this.updated.replace(/\s\w*$/, ""); // 2019-11-26 10:58:09 +0300 MSK -> 2019-11-26 10:58:09 +0300 to pass into Date()
const updatedDate = new Date(updated).getTime();
@@ -194,11 +121,67 @@ export class HelmRelease implements ItemObject {
// Helm does not store from what repository the release is installed,
// so we have to try to guess it by searching charts
async getRepo() {
async getRepo(): Promise<string> {
const chartName = this.getChart();
const version = this.getVersion();
const versions = await helmChartStore.getVersions(chartName);
const chartVersion = versions.find(chartVersion => chartVersion.version === version);
return chartVersion ? chartVersion.repo : "";
return chartVersion?.repo || "";
}
}
export const helmReleasesApi = {
async list(namespace?: string): Promise<HelmRelease[]> {
const releases = await apiKubeHelm.get<HelmRelease[]>(endpoint({ namespace }));
return releases.map(data => new HelmRelease(data));
},
async get(name: string, namespace: string): Promise<ReleaseInfo> {
const path = endpoint({ name, namespace });
const details = await apiKubeHelm.get<ReleaseRawDetails>(path);
const items: KubeObject[] = JSON.parse(details.resources).items;
const resources = items.map(item => new KubeObject(item));
return {
...details,
resources
};
},
create(payload: ReleaseCreatePayload): Promise<ReleaseUpdateDetails> {
const { repo, ...data } = payload;
data.chart = `${repo}/${data.chart}`;
data.values = jsYaml.safeLoad(data.values);
return apiKubeHelm.post(endpoint(), { data });
},
update(name: string, namespace: string, payload: ReleaseUpdatePayload): Promise<ReleaseUpdateDetails> {
const { repo, ...data } = payload;
data.chart = `${repo}/${data.chart}`;
data.values = jsYaml.safeLoad(data.values);
return apiKubeHelm.put(endpoint({ name, namespace }), { data });
},
delete(name: string, namespace: string): CancelablePromise<KubeJsonApiData> {
const path = endpoint({ name, namespace });
return apiKubeHelm.del(path);
},
getValues(name: string, namespace: string): CancelablePromise<string> {
const path = endpoint({ name, namespace }) + "/values";
return apiKubeHelm.get<string>(path);
},
getHistory(name: string, namespace: string): Promise<ReleaseRevision[]> {
const path = endpoint({ name, namespace }) + "/history";
return apiKubeHelm.get(path);
},
rollback(name: string, namespace: string, revision: number): CancelablePromise<KubeJsonApiData> {
const path = endpoint({ name, namespace }) + "/rollback";
return apiKubeHelm.put(path, {
data: {
revision: revision
}
});
}
};
+32 -39
View File
@@ -22,7 +22,7 @@ export type IHpaMetricData<T = any> = T & {
targetAverageValue?: string;
}
export interface IHpaMetric {
export interface HpaMetric {
[kind: string]: IHpaMetricData;
type: HpaMetricType;
@@ -38,6 +38,19 @@ export interface IHpaMetric {
}>;
}
export interface PodStatusCondition {
lastTransitionTime: string;
message: string;
reason: string;
status: string;
type: string;
}
export interface PodCondition extends PodStatusCondition {
isReady: boolean;
tooltip: string;
}
export class HorizontalPodAutoscaler extends KubeObject {
static kind = "HorizontalPodAutoscaler";
@@ -49,58 +62,34 @@ export class HorizontalPodAutoscaler extends KubeObject {
};
minReplicas: number;
maxReplicas: number;
metrics: IHpaMetric[];
metrics: HpaMetric[];
}
status: {
currentReplicas: number;
desiredReplicas: number;
currentMetrics: IHpaMetric[];
conditions: {
lastTransitionTime: string;
message: string;
reason: string;
status: string;
type: string;
}[];
currentMetrics: HpaMetric[];
conditions: PodStatusCondition[];
}
getMaxPods() {
return this.spec.maxReplicas || 0;
}
getMinPods() {
return this.spec.minReplicas || 0;
}
getReplicas() {
return this.status.currentReplicas;
}
getConditions() {
if (!this.status.conditions) return [];
getConditions(): PodCondition[] {
if (!this.status.conditions) {
return [];
}
return this.status.conditions.map(condition => {
const { message, reason, lastTransitionTime, status } = condition;
return {
...condition,
isReady: status === "True",
tooltip: `${message || reason} (${lastTransitionTime})`
}
};
});
}
getMetrics() {
return this.spec.metrics || [];
}
getCurrentMetrics() {
return this.status.currentMetrics || [];
}
protected getMetricName(metric: IHpaMetric): string {
protected getMetricName(metric: HpaMetric): string {
const { type, resource, pods, object, external } = metric;
switch (type) {
case HpaMetricType.Resource:
return resource.name
return resource.name;
case HpaMetricType.Pods:
return pods.metricName;
case HpaMetricType.Object:
@@ -111,9 +100,9 @@ export class HorizontalPodAutoscaler extends KubeObject {
}
// todo: refactor
getMetricValues(metric: IHpaMetric): string {
getMetricValues(metric: HpaMetric): string {
const metricType = metric.type.toLowerCase();
const currentMetric = this.getCurrentMetrics().find(current =>
const currentMetric = this.status.currentMetrics.find(current =>
metric.type == current.type && this.getMetricName(metric) == this.getMetricName(current)
);
const current = currentMetric ? currentMetric[metricType] : null;
@@ -122,11 +111,15 @@ export class HorizontalPodAutoscaler extends KubeObject {
let targetValue = "unknown";
if (current) {
currentValue = current.currentAverageUtilization || current.currentAverageValue || current.currentValue;
if (current.currentAverageUtilization) currentValue += "%";
if (current.currentAverageUtilization) {
currentValue += "%";
}
}
if (target) {
targetValue = target.targetAverageUtilization || target.targetAverageValue || target.targetValue;
if (target.targetAverageUtilization) targetValue += "%"
if (target.targetAverageUtilization) {
targetValue += "%";
}
}
return `${currentValue} / ${targetValue}`;
}
+29 -29
View File
@@ -1,33 +1,33 @@
// Local express.js endpoints
export * from "./config.api"
export * from "./cluster.api"
export * from "./kubeconfig.api"
export * from "./config.api";
export * from "./cluster.api";
export * from "./kubeconfig.api";
// Kubernetes endpoints
// Docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.10/
export * from "./namespaces.api"
export * from "./cluster-role.api"
export * from "./cluster-role-binding.api"
export * from "./role.api"
export * from "./role-binding.api"
export * from "./secret.api"
export * from "./service-accounts.api"
export * from "./nodes.api"
export * from "./pods.api"
export * from "./deployment.api"
export * from "./daemon-set.api"
export * from "./stateful-set.api"
export * from "./replica-set.api"
export * from "./job.api"
export * from "./cron-job.api"
export * from "./configmap.api"
export * from "./ingress.api"
export * from "./network-policy.api"
export * from "./persistent-volume-claims.api"
export * from "./persistent-volume.api"
export * from "./service.api"
export * from "./endpoint.api"
export * from "./storage-class.api"
export * from "./pod-metrics.api"
export * from "./podsecuritypolicy.api"
export * from "./selfsubjectrulesreviews.api"
export * from "./namespaces.api";
export * from "./cluster-role.api";
export * from "./cluster-role-binding.api";
export * from "./role.api";
export * from "./role-binding.api";
export * from "./secret.api";
export * from "./service-accounts.api";
export * from "./nodes.api";
export * from "./pods.api";
export * from "./deployment.api";
export * from "./daemon-set.api";
export * from "./stateful-set.api";
export * from "./replica-set.api";
export * from "./job.api";
export * from "./cron-job.api";
export * from "./configmap.api";
export * from "./ingress.api";
export * from "./network-policy.api";
export * from "./persistent-volume-claims.api";
export * from "./persistent-volume.api";
export * from "./service.api";
export * from "./endpoint.api";
export * from "./storage-class.api";
export * from "./pod-metrics.api";
export * from "./podsecuritypolicy.api";
export * from "./selfsubjectrulesreviews.api";
+32 -29
View File
@@ -1,11 +1,11 @@
import { KubeObject } from "../kube-object";
import { autobind } from "../../utils";
import { IMetrics, metricsApi } from "./metrics.api";
import { Metrics, metricsApi } from "./metrics.api";
import { KubeApi } from "../kube-api";
export class IngressApi extends KubeApi<Ingress> {
getMetrics(ingress: string, namespace: string): Promise<IIngressMetrics> {
const opts = { category: "ingress", ingress }
getMetrics(ingress: string, namespace: string): Promise<IngressMetrics> {
const opts = { category: "ingress", ingress };
return metricsApi.getMetrics({
bytesSentSuccess: opts,
bytesSentFailure: opts,
@@ -17,7 +17,7 @@ export class IngressApi extends KubeApi<Ingress> {
}
}
export interface IIngressMetrics<T = IMetrics> {
export interface IngressMetrics<T = Metrics> {
[metric: string]: T;
bytesSentSuccess: T;
bytesSentFailure: T;
@@ -56,52 +56,55 @@ export class Ingress extends KubeObject {
};
}
getRoutes() {
const { spec: { tls, rules } } = this
if (!rules) return []
getRoutes(): string[] {
const { spec: { tls, rules } } = this;
if (!rules) {
return [];
}
let protocol = "http"
const routes: string[] = []
let protocol = "http";
const routes: string[] = [];
if (tls && tls.length > 0) {
protocol += "s"
protocol += "s";
}
rules.map(rule => {
const host = rule.host ? rule.host : "*"
const host = rule.host ? rule.host : "*";
if (rule.http && rule.http.paths) {
rule.http.paths.forEach(path => {
routes.push(protocol + "://" + host + (path.path || "/") + " ⇢ " + path.backend.serviceName + ":" + path.backend.servicePort)
})
routes.push(protocol + "://" + host + (path.path || "/") + " ⇢ " + path.backend.serviceName + ":" + path.backend.servicePort);
});
}
})
});
return routes;
}
getHosts() {
const { spec: { rules } } = this
if (!rules) return []
return rules.filter(rule => rule.host).map(rule => rule.host)
getHosts(): string[] {
const { spec: { rules } } = this;
if (!rules) {
return [];
}
return rules.filter(rule => rule.host).map(rule => rule.host);
}
getPorts() {
const ports: number[] = []
const { spec: { tls, rules, backend } } = this
const httpPort = 80
const tlsPort = 443
getPorts(): string {
const ports: number[] = [];
const { spec: { tls, rules, backend } } = this;
const httpPort = 80;
const tlsPort = 443;
if (rules && rules.length > 0) {
if (rules.some(rule => rule.hasOwnProperty("http"))) {
ports.push(httpPort)
ports.push(httpPort);
}
}
else {
} else {
if (backend && backend.servicePort) {
ports.push(backend.servicePort)
ports.push(backend.servicePort);
}
}
if (tls && tls.length > 0) {
ports.push(tlsPort)
ports.push(tlsPort);
}
return ports.join(", ")
return ports.join(", ");
}
}
+26 -28
View File
@@ -1,9 +1,19 @@
import get from "lodash/get";
import { autobind } from "../../utils";
import { IAffinity, WorkloadKubeObject } from "../workload-kube-object";
import { IPodContainer } from "./pods.api";
import { Affinity, WorkloadKubeObject } from "../workload-kube-object";
import { PodContainer } from "./pods.api";
import { KubeApi } from "../kube-api";
import { JsonApiParams } from "../json-api";
import { CancelablePromise } from "client/utils/cancelableFetch";
import { KubeJsonApiData } from "../kube-json-api";
export interface JobCondition {
type: string;
status: string;
lastProbeTime: string;
lastTransitionTime: string;
message?: string;
}
@autobind()
export class Job extends WorkloadKubeObject {
@@ -26,12 +36,12 @@ export class Job extends WorkloadKubeObject {
};
};
spec: {
containers: IPodContainer[];
containers: PodContainer[];
restartPolicy: string;
terminationGracePeriodSeconds: number;
dnsPolicy: string;
hostPID: boolean;
affinity?: IAffinity;
affinity?: Affinity;
nodeSelector?: {
[selector: string]: string;
};
@@ -44,7 +54,7 @@ export class Job extends WorkloadKubeObject {
schedulerName: string;
};
};
containers?: IPodContainer[];
containers?: PodContainer[];
restartPolicy?: string;
terminationGracePeriodSeconds?: number;
dnsPolicy?: string;
@@ -53,48 +63,36 @@ export class Job extends WorkloadKubeObject {
schedulerName?: string;
}
status: {
conditions: {
type: string;
status: string;
lastProbeTime: string;
lastTransitionTime: string;
message?: string;
}[];
conditions: JobCondition[];
startTime: string;
completionTime: string;
succeeded: number;
}
getDesiredCompletions() {
getDesiredCompletions(): number {
return this.spec.completions || 0;
}
getCompletions() {
getCompletions(): number {
return this.status.succeeded || 0;
}
getParallelism() {
return this.spec.parallelism;
}
getCondition() {
getCondition(): JobCondition {
// Type of Job condition could be only Complete or Failed
// https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.14/#jobcondition-v1-batch
const { conditions } = this.status;
if (!conditions) return;
return conditions.find(({ status }) => status === "True");
return this.status.conditions.find(({ status }) => status === "True");
}
getImages() {
const containers: IPodContainer[] = get(this, "spec.template.spec.containers", [])
return [...containers].map(container => container.image)
getImages(): string[] {
const containers: PodContainer[] = get(this, "spec.template.spec.containers", []);
return containers.map(container => container.image);
}
delete() {
delete(): CancelablePromise<KubeJsonApiData> {
const params: JsonApiParams = {
query: { propagationPolicy: "Background" }
}
return super.delete(params)
};
return super.delete(params);
}
}
@@ -1,12 +1,14 @@
// Kubeconfig api
import { apiBase } from "../index";
import { CancelablePromise } from "client/utils/cancelableFetch";
import { JsonApiData } from "../json-api";
export const kubeConfigApi = {
getUserConfig() {
getUserConfig(): CancelablePromise<JsonApiData> {
return apiBase.get("/kubeconfig/user");
},
getServiceAccountConfig(account: string, namespace: string) {
getServiceAccountConfig(account: string, namespace: string): CancelablePromise<JsonApiData> {
return apiBase.get(`/kubeconfig/service-account/${namespace}/${account}`);
},
};
+26 -18
View File
@@ -4,15 +4,15 @@ import moment from "moment";
import { apiBase } from "../index";
import { IMetricsQuery } from "../../../server/common/metrics";
export interface IMetrics {
export interface Metrics {
status: string;
data: {
resultType: string;
result: IMetricsResult[];
result: MetricsResult[];
};
}
export interface IMetricsResult {
export interface MetricsResult {
metric: {
[name: string]: string;
instance: string;
@@ -25,7 +25,7 @@ export interface IMetricsResult {
values: [number, string][];
}
export interface IMetricsReqParams {
export interface MetricsReqParams {
start?: number | string; // timestamp in seconds or valid date-string
end?: number | string;
step?: number; // step in seconds (default: 60s = each point 1m)
@@ -34,7 +34,7 @@ export interface IMetricsReqParams {
}
export const metricsApi = {
async getMetrics<T = IMetricsQuery>(query: T, reqParams: IMetricsReqParams = {}): Promise<T extends object ? { [K in keyof T]: IMetrics } : IMetrics> {
async getMetrics<T = IMetricsQuery>(query: T, reqParams: MetricsReqParams = {}): Promise<T extends object ? { [K in keyof T]: Metrics } : Metrics> {
const { range = 3600, step = 60, namespace } = reqParams;
let { start, end } = reqParams;
@@ -55,18 +55,20 @@ export const metricsApi = {
},
};
export function normalizeMetrics(metrics: IMetrics, frames = 60): IMetrics {
export function normalizeMetrics(metrics: Metrics, frames = 60): Metrics {
if (!metrics?.data?.result) {
return {
data: {
resultType: "",
result: [{
metric: {},
metric: {
instance: "",
},
values: []
} as IMetricsResult],
}],
},
status: "",
}
};
}
const { result } = metrics.data;
@@ -75,34 +77,40 @@ export function normalizeMetrics(metrics: IMetrics, frames = 60): IMetrics {
if (frames > 0) {
// fill the gaps
result.forEach(res => {
if (!res.values || !res.values.length) return;
if (!res.values || !res.values.length) {
return;
}
while (res.values.length < frames) {
const timestamp = moment.unix(res.values[0][0]).subtract(1, "minute").unix();
res.values.unshift([timestamp, "0"])
res.values.unshift([timestamp, "0"]);
}
});
}
} else {
// always return at least empty values array
result.push({
metric: {},
metric: {
instance: "",
},
values: []
} as IMetricsResult);
});
}
return metrics;
}
export function isMetricsEmpty(metrics: { [key: string]: IMetrics }) {
export function isMetricsEmpty(metrics: { [key: string]: Metrics }): boolean {
return Object.values(metrics).every(metric => !metric?.data?.result?.length);
}
export function getItemMetrics(metrics: { [key: string]: IMetrics }, itemName: string): { [key: string]: IMetrics } {
if (!metrics) return;
export function getItemMetrics(metrics: { [key: string]: Metrics }, itemName: string): { [key: string]: Metrics } {
if (!metrics) {
return;
}
const itemMetrics = { ...metrics };
for (const metric in metrics) {
if (!metrics[metric]?.data?.result) {
continue
continue;
}
const results = metrics[metric].data.result;
const result = results.find(res => Object.values(res.metric)[0] == itemName);
@@ -111,7 +119,7 @@ export function getItemMetrics(metrics: { [key: string]: IMetrics }, itemName: s
return itemMetrics;
}
export function getMetricLastPoints(metrics: { [key: string]: IMetrics }) {
export function getMetricLastPoints(metrics: { [key: string]: Metrics }): { [metric: string]: number } {
const result: Partial<{[metric: string]: number}> = {};
Object.keys(metrics).forEach(metricName => {
@@ -15,7 +15,7 @@ export class Namespace extends KubeObject {
phase: string;
}
getStatus() {
getStatus(): string {
return this.status ? this.status.phase : "-";
}
}
@@ -2,22 +2,22 @@ import { KubeObject } from "../kube-object";
import { autobind } from "../../utils";
import { KubeApi } from "../kube-api";
export interface IPolicyIpBlock {
export interface PolicyIpBlock {
cidr: string;
except?: string[];
}
export interface IPolicySelector {
export interface PolicySelector {
matchLabels: {
[label: string]: string;
};
}
export interface IPolicyIngress {
export interface PolicyIngress {
from: {
ipBlock?: IPolicyIpBlock;
namespaceSelector?: IPolicySelector;
podSelector?: IPolicySelector;
ipBlock?: PolicyIpBlock;
namespaceSelector?: PolicySelector;
podSelector?: PolicySelector;
}[];
ports: {
protocol: string;
@@ -25,9 +25,9 @@ export interface IPolicyIngress {
}[];
}
export interface IPolicyEgress {
export interface PolicyEgress {
to: {
ipBlock: IPolicyIpBlock;
ipBlock: PolicyIpBlock;
}[];
ports: {
protocol: string;
@@ -47,19 +47,23 @@ export class NetworkPolicy extends KubeObject {
};
};
policyTypes: string[];
ingress: IPolicyIngress[];
egress: IPolicyEgress[];
ingress: PolicyIngress[];
egress: PolicyEgress[];
}
getMatchLabels(): string[] {
if (!this.spec.podSelector || !this.spec.podSelector.matchLabels) return [];
if (!this.spec.podSelector || !this.spec.podSelector.matchLabels) {
return [];
}
return Object
.entries(this.spec.podSelector.matchLabels)
.map(data => data.join(":"))
.map(data => data.join(":"));
}
getTypes(): string[] {
if (!this.spec.policyTypes) return [];
if (!this.spec.policyTypes) {
return [];
}
return this.spec.policyTypes;
}
}
+55 -51
View File
@@ -1,11 +1,11 @@
import { KubeObject } from "../kube-object";
import { autobind, cpuUnitsToNumber, unitsToBytes } from "../../utils";
import { IMetrics, metricsApi } from "./metrics.api";
import { Metrics, metricsApi } from "./metrics.api";
import { KubeApi } from "../kube-api";
export class NodesApi extends KubeApi<Node> {
getMetrics(): Promise<INodeMetrics> {
const opts = { category: "nodes"}
getMetrics(): Promise<NodeMetrics> {
const opts = { category: "nodes"};
return metricsApi.getMetrics({
memoryUsage: opts,
@@ -18,7 +18,7 @@ export class NodesApi extends KubeApi<Node> {
}
}
export interface INodeMetrics<T = IMetrics> {
export interface NodeMetrics<T = Metrics> {
[metric: string]: T;
memoryUsage: T;
memoryCapacity: T;
@@ -28,6 +28,21 @@ export interface INodeMetrics<T = IMetrics> {
fsSize: T;
}
export interface NodeTaint {
key: string;
value: string;
effect: string;
}
export interface NodeConditions {
type: string;
status?: string;
lastHeartbeatTime?: string;
lastTransitionTime?: string;
reason?: string;
message?: string;
}
@autobind()
export class Node extends KubeObject {
static kind = "Node"
@@ -35,11 +50,7 @@ export class Node extends KubeObject {
spec: {
podCIDR: string;
externalID: string;
taints?: {
key: string;
value: string;
effect: string;
}[];
taints?: NodeTaint[];
unschedulable?: boolean;
}
status: {
@@ -53,14 +64,7 @@ export class Node extends KubeObject {
memory: string;
pods: string;
};
conditions: {
type: string;
status?: string;
lastHeartbeatTime?: string;
lastTransitionTime?: string;
reason?: string;
message?: string;
}[];
conditions: NodeConditions[];
addresses: {
type: string;
address: string;
@@ -83,75 +87,75 @@ export class Node extends KubeObject {
}[];
}
getNodeConditionText() {
const { conditions } = this.status
if (!conditions) return ""
return conditions.reduce((types, current) => {
if (current.status !== "True") return ""
return types += ` ${current.type}`
}, "")
getNodeConditionText(): string {
return this.status
.conditions
.filter(({status}) => status === "True")
.map(({type}) => type)
.join(" ");
}
getTaints() {
getTaints(): NodeTaint[] {
return this.spec.taints || [];
}
getRoleLabels() {
getRoleLabels(): string {
const roleLabels = Object.keys(this.metadata.labels).filter(key =>
key.includes("node-role.kubernetes.io")
).map(key => key.match(/([^/]+$)/)[0]) // all after last slash
).map(key => key.match(/([^/]+$)/)[0]); // all after last slash
if (this.metadata.labels["kubernetes.io/role"] != undefined) {
roleLabels.push(this.metadata.labels["kubernetes.io/role"])
roleLabels.push(this.metadata.labels["kubernetes.io/role"]);
}
return roleLabels.join(", ")
return roleLabels.join(", ");
}
getCpuCapacity() {
if (!this.status.capacity || !this.status.capacity.cpu) return 0
return cpuUnitsToNumber(this.status.capacity.cpu)
getCpuCapacity(): number {
if (!this.status.capacity || !this.status.capacity.cpu) {
return 0;
}
return cpuUnitsToNumber(this.status.capacity.cpu);
}
getMemoryCapacity() {
if (!this.status.capacity || !this.status.capacity.memory) return 0
return unitsToBytes(this.status.capacity.memory)
getMemoryCapacity(): number {
if (!this.status.capacity || !this.status.capacity.memory) {
return 0;
}
return unitsToBytes(this.status.capacity.memory);
}
getConditions() {
const conditions = this.status.conditions || [];
getConditions(): NodeConditions[] {
if (this.isUnschedulable()) {
return [{ type: "SchedulingDisabled", status: "True" }, ...conditions];
return [{ type: "SchedulingDisabled", status: "True" }, ...this.status.conditions];
}
return conditions;
return this.status.conditions;
}
getActiveConditions() {
getActiveConditions(): NodeConditions[] {
return this.getConditions().filter(c => c.status === "True");
}
getWarningConditions() {
const goodConditions = ["Ready", "HostUpgrades", "SchedulingDisabled"];
return this.getActiveConditions().filter(condition => {
return !goodConditions.includes(condition.type);
});
getWarningConditions(): NodeConditions[] {
const goodConditions = new Set(["Ready", "HostUpgrades", "SchedulingDisabled"]);
return this.getActiveConditions().filter(condition => !goodConditions.has(condition.type));
}
getKubeletVersion() {
getKubeletVersion(): string {
return this.status.nodeInfo.kubeletVersion;
}
getOperatingSystem(): string {
const label = this.getLabels().find(label => label.startsWith("kubernetes.io/os="))
const label = this.getLabels().find(label => label.startsWith("kubernetes.io/os="));
if (label) {
return label.split("=", 2)[1]
return label.split("=", 2)[1];
}
return "linux"
return "linux";
}
isUnschedulable() {
return this.spec.unschedulable
isUnschedulable(): boolean {
return this.spec.unschedulable;
}
}
@@ -1,11 +1,12 @@
import { KubeObject } from "../kube-object";
import { autobind } from "../../utils";
import { IMetrics, metricsApi } from "./metrics.api";
import { MatchExpression } from "../workload-kube-object";
import { Metrics, metricsApi } from "./metrics.api";
import { Pod } from "./pods.api";
import { KubeApi } from "../kube-api";
export class PersistentVolumeClaimsApi extends KubeApi<PersistentVolumeClaim> {
getMetrics(pvcName: string, namespace: string): Promise<IPvcMetrics> {
getMetrics(pvcName: string, namespace: string): Promise<PvcMetrics> {
return metricsApi.getMetrics({
diskUsage: { category: 'pvc', pvc: pvcName },
diskCapacity: { category: 'pvc', pvc: pvcName }
@@ -15,7 +16,7 @@ export class PersistentVolumeClaimsApi extends KubeApi<PersistentVolumeClaim> {
}
}
export interface IPvcMetrics<T = IMetrics> {
export interface PvcMetrics<T = Metrics> {
[key: string]: T;
diskUsage: T;
diskCapacity: T;
@@ -32,11 +33,7 @@ export class PersistentVolumeClaim extends KubeObject {
matchLabels: {
release: string;
};
matchExpressions: {
key: string; // environment,
operator: string; // In,
values: string[]; // [dev]
}[];
matchExpressions: MatchExpression[];
};
resources: {
requests: {
@@ -49,34 +46,39 @@ export class PersistentVolumeClaim extends KubeObject {
}
getPods(allPods: Pod[]): Pod[] {
const pods = allPods.filter(pod => pod.getNs() === this.getNs())
const pods = allPods.filter(pod => pod.getNs() === this.getNs());
return pods.filter(pod => {
return pod.getVolumes().filter(volume =>
volume.persistentVolumeClaim &&
volume.persistentVolumeClaim.claimName === this.getName()
).length > 0
})
).length > 0;
});
}
getStorage(): string {
if (!this.spec.resources || !this.spec.resources.requests) return "-";
if (!this.spec.resources || !this.spec.resources.requests) {
return "-";
}
return this.spec.resources.requests.storage;
}
getMatchLabels(): string[] {
if (!this.spec.selector || !this.spec.selector.matchLabels) return [];
if (!this.spec.selector || !this.spec.selector.matchLabels) {
return [];
}
return Object.entries(this.spec.selector.matchLabels)
.map(([name, val]) => `${name}:${val}`);
}
getMatchExpressions() {
if (!this.spec.selector || !this.spec.selector.matchExpressions) return [];
return this.spec.selector.matchExpressions;
getMatchExpressions(): MatchExpression[] {
return this.spec.selector?.matchExpressions;
}
getStatus(): string {
if (this.status) return this.status.phase;
return "-"
if (this.status) {
return this.status.phase;
}
return "-";
}
}
@@ -43,23 +43,23 @@ export class PersistentVolume extends KubeObject {
reason?: string;
}
getCapacity(inBytes = false) {
getCapacity(inBytes = false): number | string {
const capacity = this.spec.capacity;
if (capacity) {
if (inBytes) return unitsToBytes(capacity.storage)
if (inBytes) {
return unitsToBytes(capacity.storage);
}
return capacity.storage;
}
return 0;
}
getStatus() {
if (!this.status) return;
return this.status.phase || "-";
getStatus(): string {
return this?.status.phase || "-";
}
getClaimRefName() {
const { claimRef } = this.spec;
return claimRef ? claimRef.name : "";
getClaimRefName(): string {
return this.spec.claimRef.name;
}
}
+73 -100
View File
@@ -1,17 +1,17 @@
import { IAffinity, WorkloadKubeObject } from "../workload-kube-object";
import { Affinity, WorkloadKubeObject } from "../workload-kube-object";
import { autobind } from "../../utils";
import { IMetrics, metricsApi } from "./metrics.api";
import { Metrics, metricsApi } from "./metrics.api";
import { KubeApi } from "../kube-api";
export class PodsApi extends KubeApi<Pod> {
async getLogs(params: { namespace: string; name: string }, query?: IPodLogsQuery): Promise<string> {
async getLogs(params: { namespace: string; name: string }, query?: PodLogsQuery): Promise<string> {
const path = this.getUrl(params) + "/log";
return this.request.get(path, { query });
}
getMetrics(pods: Pod[], namespace: string, selector = "pod, namespace"): Promise<IPodMetrics> {
getMetrics(pods: Pod[], namespace: string, selector = "pod, namespace"): Promise<PodMetricsData> {
const podSelector = pods.map(pod => pod.getName()).join("|");
const opts = { category: "pods", pods: podSelector, namespace, selector }
const opts = { category: "pods", pods: podSelector, namespace, selector };
return metricsApi.getMetrics({
cpuUsage: opts,
@@ -29,7 +29,7 @@ export class PodsApi extends KubeApi<Pod> {
}
}
export interface IPodMetrics<T = IMetrics> {
export interface PodMetricsData<T = Metrics> {
[metric: string]: T;
cpuUsage: T;
cpuRequests: T;
@@ -42,7 +42,7 @@ export interface IPodMetrics<T = IMetrics> {
networkTransmit: T;
}
export interface IPodLogsQuery {
export interface PodLogsQuery {
container?: string;
tailLines?: number;
timestamps?: boolean;
@@ -58,7 +58,7 @@ export enum PodStatus {
EVICTED = "Evicted"
}
export interface IPodContainer {
export interface PodContainer {
name: string;
image: string;
command?: string[];
@@ -106,12 +106,12 @@ export interface IPodContainer {
readOnly: boolean;
mountPath: string;
}[];
livenessProbe?: IContainerProbe;
readinessProbe?: IContainerProbe;
livenessProbe?: ContainerProbe;
readinessProbe?: ContainerProbe;
imagePullPolicy: string;
}
interface IContainerProbe {
interface ContainerProbe {
httpGet?: {
path?: string;
port: number;
@@ -131,7 +131,7 @@ interface IContainerProbe {
failureThreshold?: number;
}
export interface IPodContainerStatus {
export interface PodContainerStatus {
name: string;
state: {
[index: string]: object;
@@ -173,14 +173,14 @@ export class Pod extends WorkloadKubeObject {
};
configMap: {
name: string;
}
};
secret: {
secretName: string;
defaultMode: number;
};
}[];
initContainers: IPodContainer[];
containers: IPodContainer[];
initContainers: PodContainer[];
containers: PodContainer[];
restartPolicy: string;
terminationGracePeriodSeconds: number;
dnsPolicy: string;
@@ -200,7 +200,7 @@ export class Pod extends WorkloadKubeObject {
effect: string;
tolerationSeconds: number;
}[];
affinity: IAffinity;
affinity: Affinity;
}
status: {
phase: string;
@@ -213,34 +213,29 @@ export class Pod extends WorkloadKubeObject {
hostIP: string;
podIP: string;
startTime: string;
initContainerStatuses?: IPodContainerStatus[];
containerStatuses?: IPodContainerStatus[];
initContainerStatuses?: PodContainerStatus[];
containerStatuses?: PodContainerStatus[];
qosClass: string;
reason?: string;
}
getInitContainers() {
return this.spec.initContainers || [];
getAllContainers(): PodContainer[] {
return this.spec.containers.concat(this.spec.initContainers);
}
getContainers() {
return this.spec.containers || [];
getRunningContainers(): PodContainer[] {
const activeContainers = new Set(
this.getContainerStatuses()
.filter(({ state }) => !!state.running)
.map(({ name }) => name)
);
return this.getAllContainers()
.filter(({ name }) => activeContainers.has(name));
}
getAllContainers() {
return this.getContainers().concat(this.getInitContainers());
}
getRunningContainers() {
const statuses = this.getContainerStatuses()
return this.getAllContainers().filter(container => {
return statuses.find(status => status.name === container.name && !!status.state["running"])
}
)
}
getContainerStatuses(includeInitContainers = true) {
const statuses: IPodContainerStatus[] = [];
getContainerStatuses(includeInitContainers = true): PodContainerStatus[] {
const statuses: PodContainerStatus[] = [];
const { containerStatuses, initContainerStatuses } = this.status;
if (containerStatuses) {
statuses.push(...containerStatuses);
@@ -253,28 +248,22 @@ export class Pod extends WorkloadKubeObject {
getRestartsCount(): number {
const { containerStatuses } = this.status;
if (!containerStatuses) return 0;
if (!containerStatuses) {
return 0;
}
return containerStatuses.reduce((count, item) => count + item.restartCount, 0);
}
getQosClass() {
return this.status.qosClass || "";
}
getReason() {
getReason(): string {
return this.status.reason || "";
}
getPriorityClassName() {
return this.spec.priorityClassName || "";
}
// Returns one of 5 statuses: Running, Succeeded, Pending, Failed, Evicted
getStatus() {
const phase = this.getStatusPhase();
getStatus(): PodStatus {
const phase = this.status.phase;
const reason = this.getReason();
const goodConditions = ["Initialized", "Ready"].every(condition =>
!!this.getConditions().find(item => item.type === condition && item.status === "True")
!!this.status.conditions.find(item => item.type === condition && item.status === "True")
);
if (reason === PodStatus.EVICTED) {
return PodStatus.EVICTED;
@@ -292,9 +281,13 @@ export class Pod extends WorkloadKubeObject {
}
// Returns pod phase or container error if occured
getStatusMessage() {
if (this.getReason() === PodStatus.EVICTED) return "Evicted";
if (this.getStatus() === PodStatus.RUNNING && this.metadata.deletionTimestamp) return "Terminating";
getStatusMessage(): string {
if (this.getReason() === PodStatus.EVICTED) {
return "Evicted";
}
if (this.getStatus() === PodStatus.RUNNING && this.metadata.deletionTimestamp) {
return "Terminating";
}
let message = "";
const statuses = this.getContainerStatuses(false); // not including initContainers
@@ -309,74 +302,61 @@ export class Pod extends WorkloadKubeObject {
const { reason } = state.terminated;
message = reason ? reason : "Terminated";
}
})
});
}
if (message) return message;
return this.getStatusPhase();
}
getStatusPhase() {
if (message) {
return message;
}
return this.status.phase;
}
getConditions() {
return this.status.conditions || [];
}
getVolumes() {
return this.spec.volumes || [];
}
getSecrets(): string[] {
return this.getVolumes()
return this.spec.volumes
.filter(vol => vol.secret)
.map(vol => vol.secret.secretName);
}
getNodeSelectors(): string[] {
const { nodeSelector } = this.spec
if (!nodeSelector) return []
return Object.entries(nodeSelector).map(values => values.join(": "))
const { nodeSelector } = this.spec;
if (!nodeSelector) {
return [];
}
return Object.entries(nodeSelector).map(values => values.join(": "));
}
getTolerations() {
return this.spec.tolerations || []
}
getAffinity(): IAffinity {
return this.spec.affinity
}
hasIssues() {
const notReady = !!this.getConditions().find(condition => {
return condition.type == "Ready" && condition.status !== "True"
hasIssues(): boolean {
const notReady = !!this.status.conditions.find(condition => {
return condition.type == "Ready" && condition.status !== "True";
});
const crashLoop = !!this.getContainerStatuses().find(condition => {
const waiting = condition.state.waiting
return (waiting && waiting.reason == "CrashLoopBackOff")
})
const waiting = condition.state.waiting;
return (waiting && waiting.reason == "CrashLoopBackOff");
});
return (
notReady ||
crashLoop ||
this.getStatusPhase() !== "Running"
)
this.status.phase !== "Running"
);
}
getLivenessProbe(container: IPodContainer) {
getLivenessProbe(container: PodContainer): string[] {
return this.getProbe(container.livenessProbe);
}
getReadinessProbe(container: IPodContainer) {
getReadinessProbe(container: PodContainer): string[] {
return this.getProbe(container.readinessProbe);
}
getProbe(probeData: IContainerProbe) {
if (!probeData) return [];
getProbe(probeData: ContainerProbe): string[] {
if (!probeData) {
return [];
}
const {
httpGet, exec, tcpSocket, initialDelaySeconds, timeoutSeconds,
periodSeconds, successThreshold, failureThreshold
} = probeData;
const probe = [];
const probe: string[] = [];
// HTTP Request
if (httpGet) {
const { path, port, host, scheme } = httpGet;
@@ -403,15 +383,8 @@ export class Pod extends WorkloadKubeObject {
return probe;
}
getNodeName() {
return this.spec?.nodeName
}
getSelectedNodeOs() {
if (!this.spec.nodeSelector) return
if (!this.spec.nodeSelector["kubernetes.io/os"] && !this.spec.nodeSelector["beta.kubernetes.io/os"]) return
return this.spec.nodeSelector["kubernetes.io/os"] || this.spec.nodeSelector["beta.kubernetes.io/os"]
getSelectedNodeOs(): string | null {
return this.spec?.nodeSelector?.["kubernetes.io/os"] || this.spec?.nodeSelector?.["beta.kubernetes.io/os"] || null;
}
}
@@ -2,6 +2,14 @@ import { autobind } from "../../utils";
import { KubeObject } from "../kube-object";
import { KubeApi } from "../kube-api";
export interface Rules {
fsGroup: string;
runAsGroup: string;
runAsUser: string;
supplementalGroups: string;
seLinux: string;
}
@autobind()
export class PodSecurityPolicy extends KubeObject {
static kind = "PodSecurityPolicy"
@@ -66,22 +74,22 @@ export class PodSecurityPolicy extends KubeObject {
volumes?: string[];
}
isPrivileged() {
isPrivileged(): boolean {
return !!this.spec.privileged;
}
getVolumes() {
getVolumes(): string[] {
return this.spec.volumes || [];
}
getRules() {
getRules(): Rules {
const { fsGroup, runAsGroup, runAsUser, supplementalGroups, seLinux } = this.spec;
return {
fsGroup: fsGroup ? fsGroup.rule : "",
runAsGroup: runAsGroup ? runAsGroup.rule : "",
runAsUser: runAsUser ? runAsUser.rule : "",
supplementalGroups: supplementalGroups ? supplementalGroups.rule : "",
seLinux: seLinux ? seLinux.rule : "",
fsGroup: fsGroup?.rule || "",
runAsGroup: runAsGroup?.rule || "",
runAsUser: runAsUser?.rule || "",
supplementalGroups: supplementalGroups?.rule || "",
seLinux: seLinux?.rule || "",
};
}
}
@@ -1,7 +1,7 @@
import get from "lodash/get";
import { autobind } from "../../utils";
import { IAffinity, WorkloadKubeObject } from "../workload-kube-object";
import { IPodContainer } from "./pods.api";
import { Affinity, WorkloadKubeObject } from "../workload-kube-object";
import { PodContainer } from "./pods.api";
import { KubeApi } from "../kube-api";
@autobind()
@@ -15,10 +15,10 @@ export class ReplicaSet extends WorkloadKubeObject {
[key: string]: string;
};
};
containers?: IPodContainer[];
containers?: PodContainer[];
template?: {
spec?: {
affinity?: IAffinity;
affinity?: Affinity;
nodeSelector?: {
[selector: string]: string;
};
@@ -28,7 +28,7 @@ export class ReplicaSet extends WorkloadKubeObject {
effect: string;
tolerationSeconds: number;
}[];
containers: IPodContainer[];
containers: PodContainer[];
};
};
restartPolicy?: string;
@@ -44,9 +44,9 @@ export class ReplicaSet extends WorkloadKubeObject {
observedGeneration: number;
}
getImages() {
const containers: IPodContainer[] = get(this, "spec.template.spec.containers", [])
return [...containers].map(container => container.image)
getImages(): string[] {
const containers: PodContainer[] = get(this, "spec.template.spec.containers", []);
return containers.map(container => container.image);
}
}
@@ -1,4 +1,4 @@
import jsYaml from "js-yaml"
import jsYaml from "js-yaml";
import { KubeObject } from "../kube-object";
import { KubeJsonApiData } from "../kube-json-api";
import { apiKubeResourceApplier } from "../index";
@@ -2,7 +2,7 @@ import { KubeObject } from "../kube-object";
import { KubeApi } from "../kube-api";
import { KubeJsonApiData } from "../kube-json-api";
export interface IResourceQuotaValues {
export interface ResourceQuotaValues {
[quota: string]: string;
// Compute Resource Quota
@@ -30,33 +30,34 @@ export interface IResourceQuotaValues {
"count/deployments.extensions"?: string;
}
interface MatchExpression {
operator: string;
scopeName: string;
values: string[];
}
export class ResourceQuota extends KubeObject {
static kind = "ResourceQuota"
constructor(data: KubeJsonApiData) {
super(data);
this.spec = this.spec || {} as any
this.spec = this.spec || {} as any;
}
spec: {
hard: IResourceQuotaValues;
hard: ResourceQuotaValues;
scopeSelector?: {
matchExpressions: {
operator: string;
scopeName: string;
values: string[];
}[];
matchExpressions: MatchExpression[];
};
}
status: {
hard: IResourceQuotaValues;
used: IResourceQuotaValues;
hard: ResourceQuotaValues;
used: ResourceQuotaValues;
}
getScopeSelector() {
const { matchExpressions = [] } = this.spec.scopeSelector || {};
return matchExpressions;
getScopeSelector(): MatchExpression[] {
return this.spec?.scopeSelector?.matchExpressions;
}
}
@@ -2,7 +2,7 @@ import { autobind } from "../../utils";
import { KubeObject } from "../kube-object";
import { KubeApi } from "../kube-api";
export interface IRoleBindingSubject {
export interface RoleBindingSubject {
kind: string;
name: string;
namespace?: string;
@@ -13,19 +13,19 @@ export interface IRoleBindingSubject {
export class RoleBinding extends KubeObject {
static kind = "RoleBinding"
subjects?: IRoleBindingSubject[]
subjects?: RoleBindingSubject[]
roleRef: {
kind: string;
name: string;
apiGroup?: string;
}
getSubjects() {
getSubjects(): RoleBindingSubject[] {
return this.subjects || [];
}
getSubjectNames(): string {
return this.getSubjects().map(subject => subject.name).join(", ")
return this.getSubjects().map(subject => subject.name).join(", ");
}
}
+10 -8
View File
@@ -1,18 +1,20 @@
import { KubeObject } from "../kube-object";
import { KubeApi } from "../kube-api";
export interface Rule {
verbs: string[];
apiGroups: string[];
resources: string[];
resourceNames?: string[];
}
export class Role extends KubeObject {
static kind = "Role"
rules: {
verbs: string[];
apiGroups: string[];
resources: string[];
resourceNames?: string[];
}[]
rules: Rule[]
getRules() {
return this.rules || [];
getRules(): Rule[] {
return this.rules;
}
}
+1 -5
View File
@@ -14,7 +14,7 @@ export enum SecretType {
BootstrapToken = "bootstrap.kubernetes.io/token",
}
export interface ISecretRef {
export interface SecretRef {
key?: string;
name: string;
}
@@ -37,10 +37,6 @@ export class Secret extends KubeObject {
getKeys(): string[] {
return Object.keys(this.data);
}
getToken() {
return this.data.token;
}
}
export const secretsApi = new KubeApi({
@@ -12,7 +12,7 @@ export class SelfSubjectRulesReviewApi extends KubeApi<SelfSubjectRulesReview> {
}
}
export interface ISelfSubjectReviewRule {
export interface SelfSubjectReviewRule {
verbs: string[];
apiGroups?: string[];
resources?: string[];
@@ -29,22 +29,22 @@ export class SelfSubjectRulesReview extends KubeObject {
}
status: {
resourceRules: ISelfSubjectReviewRule[];
nonResourceRules: ISelfSubjectReviewRule[];
resourceRules: SelfSubjectReviewRule[];
nonResourceRules: SelfSubjectReviewRule[];
incomplete: boolean;
}
getResourceRules() {
getResourceRules(): SelfSubjectReviewRule[] {
const rules = this.status && this.status.resourceRules || [];
return rules.map(rule => this.normalize(rule));
}
getNonResourceRules() {
getNonResourceRules(): SelfSubjectReviewRule[] {
const rules = this.status && this.status.nonResourceRules || [];
return rules.map(rule => this.normalize(rule));
}
protected normalize(rule: ISelfSubjectReviewRule): ISelfSubjectReviewRule {
protected normalize(rule: SelfSubjectReviewRule): SelfSubjectReviewRule {
const { apiGroups = [], resourceNames = [], verbs = [], nonResourceURLs = [], resources = [] } = rule;
return {
apiGroups,
@@ -56,7 +56,7 @@ export class SelfSubjectRulesReview extends KubeObject {
const separator = apiGroup == "" ? "" : ".";
return resource + separator + apiGroup;
})
}
};
}
}
@@ -2,22 +2,26 @@ import { autobind } from "../../utils";
import { KubeObject } from "../kube-object";
import { KubeApi } from "../kube-api";
export interface ImagePullSecret {
name: string;
}
export interface Secret {
name: string;
}
@autobind()
export class ServiceAccount extends KubeObject {
static kind = "ServiceAccount";
secrets?: {
name: string;
}[]
imagePullSecrets?: {
name: string;
}[]
secrets?: Secret[]
imagePullSecrets?: ImagePullSecret[]
getSecrets() {
getSecrets(): Secret[] {
return this.secrets || [];
}
getImagePullSecrets() {
getImagePullSecrets(): ImagePullSecret[] {
return this.imagePullSecrets || [];
}
}
+23 -29
View File
@@ -2,25 +2,25 @@ import { autobind } from "../../utils";
import { KubeObject } from "../kube-object";
import { KubeApi } from "../kube-api";
export interface IServicePort {
export interface ServicePort {
name?: string;
protocol: string;
port: number;
targetPort: number;
}
export class ServicePort implements IServicePort {
export class ServicePort implements ServicePort {
name?: string;
protocol: string;
port: number;
targetPort: number;
nodePort?: number;
constructor(data: IServicePort) {
Object.assign(this, data)
constructor(data: ServicePort) {
Object.assign(this, data);
}
toString() {
toString(): string {
if (this.nodePort) {
return `${this.port}:${this.nodePort}/${this.protocol}`;
} else {
@@ -29,6 +29,13 @@ export class ServicePort implements IServicePort {
}
}
export interface LoadBalancer {
ingress?: {
ip?: string;
hostname?: string;
}[];
}
@autobind()
export class Service extends KubeObject {
static kind = "Service"
@@ -45,32 +52,23 @@ export class Service extends KubeObject {
}
status: {
loadBalancer?: {
ingress?: {
ip?: string;
hostname?: string;
}[];
};
loadBalancer?: LoadBalancer;
}
getClusterIp() {
return this.spec.clusterIP;
getExternalIps(): string[] {
return this.status.loadBalancer?.ingress?.map((val): string => val.ip || val.hostname || "")
|| this.spec.externalIPs
|| [];
}
getExternalIps() {
const lb = this.getLoadBalancer();
if (lb && lb.ingress) {
return lb.ingress.map(val => val.ip || val.hostname)
}
return this.spec.externalIPs || [];
}
getType() {
getType(): string {
return this.spec.type || "-";
}
getSelector(): string[] {
if (!this.spec.selector) return [];
if (!this.spec.selector) {
return [];
}
return Object.entries(this.spec.selector).map(val => val.join("="));
}
@@ -79,15 +77,11 @@ export class Service extends KubeObject {
return ports.map(p => new ServicePort(p));
}
getLoadBalancer() {
return this.status.loadBalancer;
}
isActive() {
isActive(): boolean {
return this.getType() !== "LoadBalancer" || this.getExternalIps().length > 0;
}
getStatus() {
getStatus(): "Active" | "Pending" {
return this.isActive() ? "Active" : "Pending";
}
}
@@ -1,6 +1,6 @@
import get from "lodash/get";
import { IPodContainer } from "./pods.api";
import { IAffinity, WorkloadKubeObject } from "../workload-kube-object";
import { PodContainer } from "./pods.api";
import { Affinity, WorkloadKubeObject } from "../workload-kube-object";
import { autobind } from "../../utils";
import { KubeApi } from "../kube-api";
@@ -35,7 +35,7 @@ export class StatefulSet extends WorkloadKubeObject {
mountPath: string;
}[];
}[];
affinity?: IAffinity;
affinity?: Affinity;
nodeSelector?: {
[selector: string]: string;
};
@@ -70,9 +70,9 @@ export class StatefulSet extends WorkloadKubeObject {
collisionCount: number;
}
getImages() {
const containers: IPodContainer[] = get(this, "spec.template.spec.containers", [])
return [...containers].map(container => container.image)
getImages(): string[] {
const containers: PodContainer[] = get(this, "spec.template.spec.containers", []);
return containers.map(container => container.image);
}
}
@@ -14,20 +14,20 @@ export class StorageClass extends KubeObject {
[param: string]: string; // every provisioner has own set of these parameters
}
isDefault() {
isDefault(): boolean {
const annotations = this.metadata.annotations || {};
return (
annotations["storageclass.kubernetes.io/is-default-class"] === "true" ||
annotations["storageclass.beta.kubernetes.io/is-default-class"] === "true"
)
);
}
getVolumeBindingMode() {
return this.volumeBindingMode || "-"
getVolumeBindingMode(): string {
return this.volumeBindingMode || "-";
}
getReclaimPolicy() {
return this.reclaimPolicy || "-"
getReclaimPolicy(): string {
return this.reclaimPolicy || "-";
}
}