-
Notifications
You must be signed in to change notification settings - Fork 618
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bug 1838658: Use new proxy to connect to cloudshell in terminal #5428
Bug 1838658: Use new proxy to connect to cloudshell in terminal #5428
Conversation
3e9accc
to
1ab4cc1
Compare
@@ -86,3 +87,13 @@ export const newCloudShellWorkSpace = ( | |||
}, | |||
}, | |||
}); | |||
|
|||
export const makeTerminalInitCalls = (username, wname, wnamespace) => { | |||
const consumeUrl = `api/terminal/${wnamespace}/${wname}/exec/init`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const consumeUrl = `api/terminal/${wnamespace}/${wname}/exec/init`; | |
const consumeUrl = `/api/terminal/${wnamespace}/${wname}/exec/init`; |
@@ -35,7 +35,7 @@ describe('CloudShellTerminal', () => { | |||
true, | |||
]); | |||
const wrapper = shallow(<InternalCloudShellTerminal username="user" />); | |||
const frame = wrapper.find(CloudShellTerminalFrame); | |||
const exec = wrapper.find(CloudShellTerminalFrame); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change breaks the test.
But didn't you delete the file related these tests?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am yet to update the tests
XTerminal.applyAddon(fit); | ||
XTerminal.applyAddon(full); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use loadAddon
api: https://github.com/xtermjs/xterm.js#addons
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not supported in the current xterm dependency(3.12, requires ^3.14) and after upgrading the dependency, I am observing problems in PodExec (not sure if it is related to the version)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok fair enough, i thought it was in 3.x.
style={{ | ||
width: '100%', | ||
height: '100%', | ||
padding: this.padding / 2, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assign padding using the terminal element, otherwise the scrollbars are indented.
https://github.com/xtermjs/xterm.js/pull/1208/files
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've removed padding and added to the xterm options, but it doesn't appear to add
<div ref={this.outerRef} className={this.props.className}> | ||
<div | ||
ref={this.innerRef} | ||
style={{ width: this.state.width, height: this.state.height }} | ||
className="console" | ||
/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should only need the one div
and not 3.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just one div now
const containers = _.get(nextProps.obj, 'spec.containers', []).map((n) => n.name); | ||
if (_.isEqual(containers, prevState.containers)) { | ||
return null; | ||
} | ||
return { containers }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nextProps.obj
isn't even defined in CloudShellExecProps
.
This function does nothing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will remove this
current && current.onConnectionClosed(`connecting to ${container}`); | ||
} | ||
|
||
const impersonate = store.getState().UI.get('impersonate', {}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't reach for global redux store. Use connect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
passed this on to connect
if (this.ws) { | ||
this.ws.destroy(); | ||
const { current } = this.terminal; | ||
current && current.onConnectionClosed(`connecting to ${container}`); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unreachable code. connect
is only ever called once on mount.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
|
||
connect = () => { | ||
const { container, podname, namespace, shcommand } = this.props; | ||
const usedClient = this.props.flags[FLAGS.OPENSHIFT] ? 'oc' : 'kubectl'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent access of this.props
. Line above deconstructs all props.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
@@ -86,3 +87,13 @@ export const newCloudShellWorkSpace = ( | |||
}, | |||
}, | |||
}); | |||
|
|||
export const makeTerminalInitCalls = (username, wname, wnamespace) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
export const makeTerminalInitCalls = (username, wname, wnamespace) => { | |
export const initializeTerminal = (username: string, workspaceName: string, namespace: string): Promise<...> => { |
Promise
should be properly typed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added type
64afd8d
to
5fac5be
Compare
|
||
onResize() { | ||
try { | ||
this.terminal && this.terminal.fit(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need this if you are using resizeObserver
to call terminal.fit()
.
this.resizeObserver = new ResizeObserver(() => { | ||
this.terminal.fit(); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or you can just call onResize
here.
this.resizeObserver = new ResizeObserver(() => { | |
this.terminal.fit(); | |
}); | |
this.resizeObserver = new ResizeObserver(this.onResize); |
} | ||
|
||
componentWillUnmount() { | ||
this.terminal && this.terminal.destroy(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You also need to disconnect the resizeobserver
when component unmounts.
this.terminal && this.terminal.destroy(); | |
this.terminal && this.terminal.destroy(); | |
this.resizeObserver && this.resizeObserver.disconnect(); |
/assign |
5fac5be
to
9e7d7cf
Compare
|
||
type TerminalProps = { | ||
onData: (data: string) => void; | ||
className?: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove. className
is not used.
type TerminalProps = { | ||
onData: (data: string) => void; | ||
className?: string; | ||
shouldResize?: boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldResize
is unnecessary as we need resize support for all use cases. Even a stand alone tab supports browser resizing.
|
||
constructor(props) { | ||
super(props); | ||
this.terminalRef = React.createRef(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move to declaration.
Missing type.
if (!terminal) { | ||
return; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
terminal
can never be undefined
here.
if ( | ||
workSpacePod?.pod && | ||
workSpacePod?.container && | ||
workSpacePod?.namespace && | ||
workSpacePod?.command | ||
) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If workspacePod
is set, isn't it a guarantee that all the props are set?
if ( | |
workSpacePod?.pod && | |
workSpacePod?.container && | |
workSpacePod?.namespace && | |
workSpacePod?.command | |
) { | |
if (workspacePod) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this will take the user to the Terminal with error as soon as workSpacePod.namespace is set up.
And this occurs before workSpacePod.pod is set. However, we can alter it after moving namespace out.
position: fixed; | ||
top: 0px; | ||
left: 0px; | ||
right: 0px; | ||
bottom: 0px; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is any of this necessary?
What's wrong with using the flex layout?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It keeps expanding beyond the screen as user puts some command
overflow: hidden; | ||
padding-bottom: var(--pf-global--spacer--xl); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't be creating extra white space at the bottom.
@@ -0,0 +1,8 @@ | |||
.odc-cloudshell-terminal { | |||
&__container { | |||
background-color: var(--pf-global--palette--black-1000); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this even exist black-1000
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same is used in log component -- var(--pf-global--palette--black-1000);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like it does exist. But I wonder if we should just use --pf-global--BackgroundColor--dark-100
instead.
cursorBlink: false, | ||
cols: 80, | ||
rows: 25, | ||
padding: 30, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think 4px
max is sufficient padding. It looks to align with UX as well. Furthermore we don't want to add more than this amount to the top and bottom.
rows: 25, | ||
padding: 30, | ||
}; | ||
this.terminal = new XTerminal(Object.assign({}, options)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.terminal = new XTerminal(Object.assign({}, options)); | |
this.terminal = new XTerminal(options); |
4550bb6
to
0bfa35f
Compare
0bfa35f
to
e6684c3
Compare
@abhinandan13jan Raised a PR on your branch with some fixes and cleanups - abhinandan13jan#2 |
855e14e
to
235ca8e
Compare
private terminal; | ||
|
||
private ws; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private terminal; | |
private ws; | |
private terminal = React.createRef<Terminal>(); | |
private ws: WSFactory; |
this.ws && this.ws.send(`0${Base64.encode(data)}`); | ||
}; | ||
|
||
connect() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
connect() { | |
private connect() { |
// error channel | ||
if (raw[0] === '3') { | ||
if (previous.includes(NO_SH)) { | ||
currentTerminal.reset(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent. Missing null check as per rest of usage of this.terminal.current
.
|
||
onConnectionClosed = (reason) => { | ||
this.terminal.write(`\x1b[31m${reason || 'disconnected'}\x1b[m\r\n`); | ||
this.terminal.cursorHidden = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cursorHidden
doesn't exist in the type def of Terminal
.
There is isCursorHidden
on core service but unsure how to reach it...
this.terminal.write(`\x1b[31m${reason || 'disconnected'}\x1b[m\r\n`); | ||
this.terminal.cursorHidden = true; | ||
this.terminal.setOption('disableStdin', true); | ||
this.terminal.refresh(this.terminal.y, this.terminal.y); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
y
don't exist in the type def of Terminal
} | ||
|
||
focus() { | ||
this.terminal && this.terminal.focus(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.terminal
is always defined.
this.terminal && this.terminal.focus(); | |
this.terminal.focus(); |
componentDidMount() { | ||
this.terminal.open(this.terminalRef.current); | ||
this.resizeObserver = new ResizeObserver(() => { | ||
window.requestAnimationFrame(() => this.terminal.fit()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To work with typescript.
Import fit like this:
import { fit } from 'xterm/lib/addons/fit/fit';
Remove XTerminal.applyAddon(fit);
window.requestAnimationFrame(() => this.terminal.fit()); | |
window.requestAnimationFrame(() => fit(this.terminal)); |
@@ -14,7 +12,7 @@ jest.mock('@console/internal/components/utils/k8s-watch-hook', () => ({ | |||
describe('CloudShellTerminal', () => { | |||
it('should display loading box', () => { | |||
(useK8sWatchResource as jest.Mock).mockReturnValueOnce([null, false]); | |||
const wrapper = shallow(<InternalCloudShellTerminal username="user" />); | |||
const wrapper = mount(<InternalCloudShellTerminal username="user" />); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We want to use shallow
rendering. Checking for LoadingBox
is no longer correct. This test needs updating.
@@ -23,21 +21,4 @@ describe('CloudShellTerminal', () => { | |||
const wrapper = shallow(<InternalCloudShellTerminal username="user" />); | |||
expect(wrapper.find(CloudShellSetup)).toHaveLength(1); | |||
}); | |||
|
|||
it('should display terminal if loaded with matching workspace', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's try to add more tests / fix up existing tests instead of removing them.
@@ -0,0 +1,8 @@ | |||
.odc-cloudshell-terminal { | |||
&__container { | |||
background-color: var(--pf-global--BackgroundColor--dark-100); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This background color is incorrect. We need pure black.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So back to black-10000
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default terminal theme background color is pure black. So whatever gets us to pure black.
Unless we choose to override. But at this point being consistent with the other terminal is probably best.
@abhinandan13jan Another PR with updates and fixes - abhinandan13jan#3 |
/retitle Bug 1838658: Use new proxy to connect to cloudshell in terminal |
@abhinandan13jan: This pull request references Bugzilla bug 1838658, which is valid. The bug has been moved to the POST state. The bug has been updated to refer to the pull request using the external bug tracker. 3 validation(s) were run on this bug
In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
/bugzilla refresh |
@rohitkrai03: This pull request references Bugzilla bug 1838658, which is valid. 3 validation(s) were run on this bug
In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
b38f1a0
to
b6de504
Compare
'Connecting to your OpenShift command line terminal ...', | ||
); | ||
}); | ||
it('should render cloudshellterminal', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test names need to be descriptive of the actual test. Looks to be a copy and paste error.
@@ -14,30 +13,19 @@ jest.mock('@console/internal/components/utils/k8s-watch-hook', () => ({ | |||
describe('CloudShellTerminal', () => { | |||
it('should display loading box', () => { | |||
(useK8sWatchResource as jest.Mock).mockReturnValueOnce([null, false]); | |||
const wrapper = shallow(<InternalCloudShellTerminal username="user" />); | |||
expect(wrapper.find(LoadingBox)).toHaveLength(1); | |||
const wrapper: ShallowWrapper = shallow(<InternalCloudShellTerminal username="user" />); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: no need to assign a type when it can be inferred from the assignment at declaration time.
const wrapper: ShallowWrapper = shallow(<InternalCloudShellTerminal username="user" />); | |
const wrapper = shallow(<InternalCloudShellTerminal username="user" />); |
React.useEffect(() => { | ||
const term: XTerminal = new XTerminal(terminalOptions); | ||
term.on('data', onData); | ||
term.open(terminalRef.current); | ||
term.focus(); | ||
|
||
const resizeObserver: ResizeObserver = new ResizeObserver(() => { | ||
window.requestAnimationFrame(() => fit(term)); | ||
}); | ||
|
||
resizeObserver.observe(terminalRef.current); | ||
|
||
if (terminal.current !== term) { | ||
terminal.current && terminal.current.destroy(); | ||
terminal.current = term; | ||
} | ||
|
||
return () => { | ||
term.destroy(); | ||
resizeObserver.disconnect(); | ||
}; | ||
}, [onData]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems harsh to re-initialize the entire terminal when onData
callback changes.
Probably want to split up into multiple effects where one does something simple like:
React.useEffect(() => {
const term = terminal.current;
term.on('data', onData);
return () => term.off('data', onData);
}, [onData]);
const focus = () => { | ||
terminal.current && terminal.current.focus(); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All the imperative handle functions should be defined inside the imperative handle hook callback so that they aren't needlessly declared on each render.
@@ -0,0 +1,8 @@ | |||
.odc-cloudshell-terminal { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.odc-cloudshell-terminal { | |
.co-cloudshell-terminal { |
onConnectionClosed, | ||
})); | ||
|
||
return <div ref={terminalRef} style={{ width: '100%', height: '100%' }} />; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
&__container { | ||
background-color: #000; | ||
color: var(--pf-global--Color--light-100); | ||
width: 100%; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: width shouldn't be needed on a block element div
return <CloudShellSetup onCancel={onCancel} />; | ||
if (loaded && !workspace) return <CloudShellSetup onCancel={onCancel} />; | ||
|
||
return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should ever return null. We have enough information to know if we should be showing loading, error, terminal or form at any point. The problem is with initDataLoading
which I don't think is necessary. We can assume loading still if we do not have initData
.
const [data, loaded, loadError] = useK8sWatchResource<CloudShellResource>(resource); | ||
const [data, loaded, loadError] = useK8sWatchResource<CloudShellResource[]>(resource); | ||
const [initData, setInitData] = React.useState<TerminalInitData>(); | ||
const [initDataLoading, setInitDataLoading] = React.useState<boolean>(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is needed if you use initData
null checks instead.
<StatusBox loaded={loaded} loadError={loadError} label="OpenShift command line terminal" /> | ||
<StatusBox | ||
loaded={loaded} | ||
loadError={loadError || initError} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
loadError
cannot be a string
as is the case for initError
.
/retest |
/approve |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/lgtm
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: abhinandan13jan, christianvogt, rohitkrai03 The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
@abhinandan13jan: All pull requests linked via external trackers have merged: openshift/console#5428. Bugzilla bug 1838658 has been moved to the MODIFIED state. In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
CloudShell Terminal using exec and autoresizer Xterm
init
call utility to make call to non k8s terminal API (requires backend changes)as per [WIP] fix(cloudshell-rework): make changes to podexec,xterm and switch to u… #5359
CloudShellTerminal
modified to makes init and derive required props from responseprops include [podname, container,command, namespace]
Linked issue
https://issues.redhat.com/browse/ODC-3793
Screenshot
Browser conformation
chrome 73