11import { makeInformer , ADD , DELETE , ERROR , UPDATE , KubernetesObject } from '@kubernetes/client-node' ;
2+
23import { logger } from '../../../common/logger' ;
34import { WorkloadKind } from '../../types' ;
45import { podWatchHandler , podDeletedHandler } from './pod' ;
@@ -9,6 +10,7 @@ import { jobWatchHandler } from './job';
910import { replicaSetWatchHandler } from './replica-set' ;
1011import { replicationControllerWatchHandler } from './replication-controller' ;
1112import { statefulSetWatchHandler } from './stateful-set' ;
13+ import { deploymentConfigWatchHandler } from './deployment-config' ;
1214import { k8sApi , kubeConfig } from '../../cluster' ;
1315import * as kubernetesApiWrappers from '../../kuberenetes-api-wrappers' ;
1416import { IWorkloadWatchMetadata , FALSY_WORKLOAD_NAME_MARKER } from './types' ;
@@ -91,9 +93,74 @@ const workloadWatchMetadata: Readonly<IWorkloadWatchMetadata> = {
9193 } ,
9294 listFactory : ( namespace ) => ( ) => k8sApi . appsClient . listNamespacedStatefulSet ( namespace ) ,
9395 } ,
96+ [ WorkloadKind . DeploymentConfig ] : {
97+ /** https://docs.openshift.com/container-platform/4.7/rest_api/workloads_apis/deploymentconfig-apps-openshift-io-v1.html */
98+ endpoint : '/apis/apps.openshift.io/v1/watch/namespaces/{namespace}/deploymentconfigs' ,
99+ handlers : {
100+ [ DELETE ] : deploymentConfigWatchHandler ,
101+ } ,
102+ listFactory : ( namespace ) => ( ) => k8sApi . customObjectsClient . listNamespacedCustomObject ( 'apps.openshift.io' , 'v1' , namespace , 'deploymentconfigs' ) ,
103+ } ,
94104} ;
95105
96- export function setupInformer ( namespace : string , workloadKind : WorkloadKind ) {
106+ async function isSupportedWorkload (
107+ namespace : string ,
108+ workloadKind : WorkloadKind ,
109+ ) : Promise < boolean > {
110+ if ( workloadKind !== WorkloadKind . DeploymentConfig ) {
111+ return true ;
112+ }
113+
114+ try {
115+ const pretty = undefined ;
116+ const continueToken = undefined ;
117+ const fieldSelector = undefined ;
118+ const labelSelector = undefined ;
119+ const limit = 1 ; // Try to grab only a single object
120+ const resourceVersion = undefined ; // List anything in the cluster
121+ const timeoutSeconds = 10 ; // Don't block the snyk-monitor indefinitely
122+ const attemptedApiCall = await kubernetesApiWrappers . retryKubernetesApiRequest (
123+ ( ) =>
124+ k8sApi . customObjectsClient . listNamespacedCustomObject (
125+ 'apps.openshift.io' ,
126+ 'v1' ,
127+ namespace ,
128+ 'deploymentconfigs' ,
129+ pretty ,
130+ continueToken ,
131+ fieldSelector ,
132+ labelSelector ,
133+ limit ,
134+ resourceVersion ,
135+ timeoutSeconds ,
136+ ) ,
137+ ) ;
138+ return (
139+ attemptedApiCall !== undefined &&
140+ attemptedApiCall . response !== undefined &&
141+ attemptedApiCall . response . statusCode !== undefined &&
142+ attemptedApiCall . response . statusCode >= 200 &&
143+ attemptedApiCall . response . statusCode < 300
144+ ) ;
145+ } catch ( error ) {
146+ logger . info (
147+ { error, workloadKind } ,
148+ 'Failed on Kubernetes API call to list DeploymentConfig' ,
149+ ) ;
150+ return false ;
151+ }
152+ }
153+
154+ export async function setupInformer ( namespace : string , workloadKind : WorkloadKind ) : Promise < void > {
155+ const isSupported = await isSupportedWorkload ( namespace , workloadKind ) ;
156+ if ( ! isSupported ) {
157+ logger . info (
158+ { namespace, workloadKind } ,
159+ 'The Kubernetes cluster does not support this workload' ,
160+ ) ;
161+ return ;
162+ }
163+
97164 const workloadMetadata = workloadWatchMetadata [ workloadKind ] ;
98165 const namespacedEndpoint = workloadMetadata . endpoint . replace ( '{namespace}' , namespace ) ;
99166
@@ -103,7 +170,10 @@ export function setupInformer(namespace: string, workloadKind: WorkloadKind) {
103170 return await kubernetesApiWrappers . retryKubernetesApiRequest (
104171 ( ) => listMethod ( ) ) ;
105172 } catch ( err ) {
106- logger . error ( { err, namespace, workloadKind} , 'error while listing entities on namespace' ) ;
173+ logger . error (
174+ { err, namespace, workloadKind } ,
175+ 'error while listing entities on namespace' ,
176+ ) ;
107177 throw err ;
108178 }
109179 } ;
@@ -113,11 +183,11 @@ export function setupInformer(namespace: string, workloadKind: WorkloadKind) {
113183 informer . on ( ERROR , ( err ) => {
114184 // Types from client library insists that callback is of type KubernetesObject
115185 if ( ( err as any ) . code === ECONNRESET_ERROR_CODE ) {
116- logger . debug ( `informer ${ ECONNRESET_ERROR_CODE } occurred, restarting informer` ) ;
186+ logger . debug ( { } , `informer ${ ECONNRESET_ERROR_CODE } occurred, restarting informer` ) ;
117187
118188 // Restart informer after 1sec
119- setTimeout ( ( ) => {
120- informer . start ( ) ;
189+ setTimeout ( async ( ) => {
190+ await informer . start ( ) ;
121191 } , 1000 ) ;
122192 } else {
123193 logger . error ( { err } , 'unexpected informer error event occurred' ) ;
@@ -135,5 +205,5 @@ export function setupInformer(namespace: string, workloadKind: WorkloadKind) {
135205 } ) ;
136206 }
137207
138- informer . start ( ) ;
208+ await informer . start ( ) ;
139209}
0 commit comments