Skip to content

Commit

Permalink
Merge pull request #10669 from richard-cox/fix-node-spam
Browse files Browse the repository at this point in the history
Handle resources that cannot be watched
  • Loading branch information
richard-cox committed Mar 27, 2024
2 parents 89d4eab + a91f030 commit d612277
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 9 deletions.
16 changes: 8 additions & 8 deletions shell/plugins/dashboard-store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,15 +156,15 @@ export default {

// No need to request the resources if we have them already
if ( opt.force !== true && (getters['haveAll'](type) || getters['haveAllNamespace'](type, opt.namespaced))) {
const args = {
type,
revision: '',
// watchNamespace - used sometimes when we haven't fetched the results of a single namespace
// namespaced - used when we have fetched the result of a single namespace (see https://github.com/rancher/dashboard/pull/7329/files)
namespace: opt.watchNamespace || opt.namespaced
};

if (opt.watch !== false ) {
const args = {
type,
revision: '',
// watchNamespace - used sometimes when we haven't fetched the results of a single namespace
// namespaced - used when we have fetched the result of a single namespace (see https://github.com/rancher/dashboard/pull/7329/files)
namespace: opt.watchNamespace || opt.namespaced
};

dispatch('watch', args);
}

Expand Down
106 changes: 106 additions & 0 deletions shell/plugins/steve/__tests__/subscribe.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { actions } from '../subscribe';

describe('steve: subscribe', () => {
describe('actions', () => {
describe('watch', () => {
const state = {};
const getters = {
normalizeType: (type: string) => type,
schemaFor: () => null,
inError: () => false,
watchStarted: () => false,
};
const rootGetters = { 'type-map/isSpoofed': () => false };

const type = 'test';
const selector = undefined;
const id = undefined;
const revision = 1;
const namespace = undefined;
const stop = false;
const force = undefined;

it('no schema', () => {
const dispatch = jest.fn();

actions.watch({
state, dispatch, getters, rootGetters
}, {
type, selector, id, revision, namespace, stop, force
});

expect(dispatch).toHaveBeenCalledWith('send', {
resourceType: type,
resourceVersion: revision.toString(),

});
});

it('schema with watch verb', () => {
const dispatch = jest.fn();
const testGetters = {
...getters,
schemaFor: (type: string) => ({ attributes: { verbs: ['watch'] } }),
};

actions.watch({
state, dispatch, getters: testGetters, rootGetters
}, {
type, selector, id, revision, namespace, stop, force
});

expect(dispatch).toHaveBeenCalledWith('send', {
resourceType: type,
resourceVersion: revision.toString(),
});
});

it('schema with no watch verb', () => {
const dispatch = jest.fn();
const testGetters = {
...getters,
schemaFor: (type: string) => ({ attributes: { verbs: [] } }),
};

actions.watch({
state, dispatch, getters: testGetters, rootGetters
}, {
type, selector, id, revision, namespace, stop, force
});

expect(dispatch).not.toHaveBeenCalled();
});

it('don\'t watch when the watch is in error', () => {
const dispatch = jest.fn();
const testGetters = {
...getters,
inError: (params: any) => true,
};

actions.watch({
state, dispatch, getters: testGetters, rootGetters
}, {
type, selector, id, revision, namespace, stop, force
});

expect(dispatch).not.toHaveBeenCalled();
});
});

describe('ws.resource.error', () => {
it('handle no permission error', () => {
const commit = jest.fn();
const getters = { storeName: 'storeName' };
const dispatch = undefined;

const msg = { data: { error: 'the server does not allow this method on the requested resource' } };

actions['ws.resource.error']({
getters, commit, dispatch
}, msg);
expect(commit).toHaveBeenCalledWith('setInError', { msg, reason: 'NO_PERMS' });
});
});
});
});
13 changes: 12 additions & 1 deletion shell/plugins/steve/subscribe.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import Socket, {
EVENT_DISCONNECT_ERROR,
NO_WATCH,
NO_SCHEMA,
REVISION_TOO_OLD
REVISION_TOO_OLD,
NO_PERMS
} from '@shell/utils/socket';
import { normalizeType } from '@shell/plugins/dashboard-store/normalize';
import day from 'dayjs';
Expand Down Expand Up @@ -430,6 +431,14 @@ const sharedActions = {
return;
}

const schema = getters.schemaFor(type, false, false);

if (!!schema?.attributes?.verbs?.includes && !schema.attributes.verbs.includes('watch')) {
state.debugSocket && console.info('Will not Watch (type does not have watch verb)', JSON.stringify(params)); // eslint-disable-line no-console

return;
}

// If socket is in error don't try to watch.... unless we `force` it
const inError = getters.inError(params);

Expand Down Expand Up @@ -857,6 +866,8 @@ const defaultActions = {
// 2) will be cleared when resyncWatch --> watch (with force) --> resource.start completes
commit('setInError', { msg, reason: REVISION_TOO_OLD });
dispatch('resyncWatch', msg);
} else if ( err.includes('the server does not allow this method on the requested resource')) {
commit('setInError', { msg, reason: NO_PERMS });
}
},

Expand Down
1 change: 1 addition & 0 deletions shell/utils/socket.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const EVENT_DISCONNECT_ERROR = 'disconnect_error';

export const NO_WATCH = 'NO_WATCH';
export const NO_SCHEMA = 'NO_SCHEMA';
export const NO_PERMS = 'NO_PERMS';
export const REVISION_TOO_OLD = 'TOO_OLD';

export default class Socket extends EventTarget {
Expand Down

0 comments on commit d612277

Please sign in to comment.