Skip to content

Commit

Permalink
live api parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
juozasg authored and Kingdon Barrett committed Jul 20, 2023
1 parent e88c991 commit 324366b
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 57 deletions.
65 changes: 65 additions & 0 deletions src/cli/kubernetes/apiResources.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { telemetry } from 'extension';
import { TelemetryError } from 'types/telemetryEventNames';
import { invokeKubectlCommand } from './kubernetesToolsKubectl';
import { Kind } from 'types/kubernetes/kubernetesTypes';


type KindApiParams = {
plural: string; // configmaps, deployments, gitrepositories, ...
group: string; // '', apps, source.toolkit.fluxcd.io, ...
version: string; // v1, v1beta2, ...
};

/*
* Current cluster supported kubernetes resource kinds.
*/
let apiResources: Map<Kind, KindApiParams> | undefined;

/**
* Return all available kubernetes resource kinds
*/
export function getAvailableResourceKinds(): Kind[] | undefined {
if(apiResources) {
return Object.keys(apiResources) as Kind[];
}
}


export function getAPIParams(kind: Kind): KindApiParams | undefined {
if(apiResources) {
return apiResources.get(kind);
}
}


export async function loadAvailableResourceKinds() {
apiResources = undefined;

const kindsShellResult = await invokeKubectlCommand('api-resources --verbs=list -o wide');
if (kindsShellResult?.code !== 0) {
telemetry.sendError(TelemetryError.FAILED_TO_GET_AVAILABLE_RESOURCE_KINDS);
console.warn(`Failed to get resource kinds: ${kindsShellResult?.stderr}`);
return;
}

const lines = kindsShellResult.stdout
.split('\n')
.filter(line => line.length).slice(1);

apiResources = new Map<Kind, KindApiParams>();

lines.map(line => {
const cols = line.split(/\s+/);
const kind = cols[4] as Kind;
const plural = cols[0];
const groupVersion = cols[2];
let [group, version] = groupVersion.split('/');
if(!version) {
version = group;
group = '';
}
apiResources?.set(kind, { plural, group, version });
});

console.log('lines', lines);
}
29 changes: 1 addition & 28 deletions src/cli/kubernetes/kubectlGet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,7 @@ import { TelemetryError } from 'types/telemetryEventNames';
import { parseJson, parseJsonItems } from 'utils/jsonUtils';
import { invokeKubectlCommand } from './kubernetesToolsKubectl';
import { informer } from 'informer/kubernetesInformer';
/*
* Current cluster supported kubernetes resource kinds.
*/
export let clusterSupportedResourceKinds: string[] | undefined;

import { getAvailableResourceKinds } from './apiResources';
/**
* RegExp for the Error that should not be sent in telemetry.
* Server doesn't have a resource type = when GitOps not enabled
Expand Down Expand Up @@ -141,30 +137,7 @@ export async function getFluxControllers(context?: string): Promise<Deployment[]
return parseJsonItems(fluxDeploymentShellResult.stdout);
}

/**
* Return all available kubernetes resource kinds.
*/
export function getAvailableResourceKinds(): string[] | undefined {
return clusterSupportedResourceKinds;
}


export async function loadAvailableResourceKinds() {
clusterSupportedResourceKinds = undefined;

const kindsShellResult = await invokeKubectlCommand('api-resources --verbs=list -o name');
if (kindsShellResult?.code !== 0) {
telemetry.sendError(TelemetryError.FAILED_TO_GET_AVAILABLE_RESOURCE_KINDS);
console.warn(`Failed to get resource kinds: ${kindsShellResult?.stderr}`);
return;
}

const kinds = kindsShellResult.stdout
.split('\n')
.filter(kind => kind.length);

clusterSupportedResourceKinds = kinds;
}

/**
* Return all kubernetes resources that were created by a kustomize/helmRelease.
Expand Down
7 changes: 3 additions & 4 deletions src/cli/kubernetes/kubernetesConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { shellCodeError } from 'cli/shell/exec';
import { setVSCodeContext, telemetry } from 'extension';
import { ContextId } from 'types/extensionIds';
import { TelemetryError } from 'types/telemetryEventNames';
import { loadAvailableResourceKinds } from './kubectlGet';
import { loadAvailableResourceKinds } from './apiResources';
import { loadKubeConfigPath } from './kubernetesConfigWatcher';
import { invokeKubectlCommand } from './kubernetesToolsKubectl';

Expand Down Expand Up @@ -87,10 +87,9 @@ export async function loadKubeConfig(forceReloadResourceKinds = false) {
if(kcChanges.currentContextChanged) {
console.log('currentContext changed', kubeConfig.getCurrentContext());
onCurrentContextChanged.fire(kubeConfig);
} else if(forceReloadResourceKinds) {
await loadAvailableResourceKinds();
}

} else if(forceReloadResourceKinds) {
await loadAvailableResourceKinds();
}
}

Expand Down
37 changes: 13 additions & 24 deletions src/informer/kubernetesInformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
// flux prerelease: /apis/source.toolkit.fluxcd.io/v1/gitrepositories

import * as k8s from '@kubernetes/client-node';
import { getAPIParams } from 'cli/kubernetes/apiResources';
import { kubeProxyConfig } from 'cli/kubernetes/kubectlProxy';
import { GitRepository } from 'types/flux/gitRepository';
import { Kind, KubernetesListObject, KubernetesObject } from 'types/kubernetes/kubernetesTypes';
Expand All @@ -16,25 +17,6 @@ import { sourceDataProvider } from 'ui/treeviews/treeViews';



type KindPlural = string;
type ApiGroup = string;
type ApiVersion = string;
type ApiEndpointParams = [KindPlural, ApiGroup, ApiVersion];

type InformerEventType = 'add' | 'update' | 'delete';
type InformerEventFunc = (event: InformerEventType, obj: KubernetesObject)=> void;

// TODO: lookup real paths
// TODO: loop for all Kind types to automate this

function getAPIPaths(kind: Kind): ApiEndpointParams {
const paths: Record<Kind, ApiEndpointParams> = {
'GitRepository': ['gitrepositories', 'source.toolkit.fluxcd.io', 'v1'],
} as Record<Kind, ApiEndpointParams>;

return paths[kind];
}


// registering an add function before informer start will fire for each existing object
// registering after the start wont fire for old objects
Expand All @@ -52,7 +34,9 @@ export async function startFluxInformer() {


informer = createInformer(Kind.GitRepository, kubeProxyConfig);

if(!informer) {
return;
}
try {
console.log('informer starting...');
await informer.start();
Expand Down Expand Up @@ -85,20 +69,25 @@ export function stopFluxInformer() {

// will start a self-healing informer for each resource type and namespaces
function createInformer(kind: Kind, kubeConfig: k8s.KubeConfig) {
// const k8sCoreApi = kc.makeApiClient(k8s.CoreV1Api);
const k8sCoreApi = kubeConfig.makeApiClient(k8s.CoreV1Api);
// k8sCoreApi.listNamespace()

const k8sCustomApi = kubeConfig.makeApiClient(k8s.CustomObjectsApi);

const [plural, group, version] = getAPIPaths(kind);
const api = getAPIParams(kind);
if(!api) {
return;
}

const listFn = async () => {
const result = await k8sCustomApi.listClusterCustomObject(group, version, plural);
const result = await k8sCustomApi.listClusterCustomObject(api.group, api.version, api.plural);
const kbody = result.body as KubernetesListObject<GitRepository>;
return Promise.resolve({response: result.response, body: kbody});
};

const k8sinformer = k8s.makeInformer(
kubeConfig,
`/apis/${group}/${version}/${plural}`,
`/apis/${api.group}/${api.version}/${api.plural}`,
listFn,
);

Expand Down
2 changes: 1 addition & 1 deletion src/ui/treeviews/treeViews.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { detectClusterProvider } from 'cli/kubernetes/clusterProvider';
import { kubeConfig, onCurrentContextChanged, onKubeConfigContextsChanged } from 'cli/kubernetes/kubernetesConfig';
import { ClusterInfo } from 'types/kubernetes/clusterProvider';
import { TemplateDataProvider } from './dataProviders/templateDataProvider';
import { loadAvailableResourceKinds } from 'cli/kubernetes/kubectlGet';
import { loadAvailableResourceKinds } from 'cli/kubernetes/apiResources';

export let clusterDataProvider: ClusterDataProvider;
export let sourceDataProvider: SourceDataProvider;
Expand Down

0 comments on commit 324366b

Please sign in to comment.