Skip to content

Commit

Permalink
Working on Terminal View
Browse files Browse the repository at this point in the history
  • Loading branch information
DerekTBrown committed Aug 4, 2017
1 parent 4ff0e14 commit ab5343b
Show file tree
Hide file tree
Showing 12 changed files with 169 additions and 54 deletions.
6 changes: 4 additions & 2 deletions both/models/session.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ export enum SessionStatus {
}

export interface Container {
name? : string,
container_ip: string,
container_dns: string,
container_id: string,
proxy_username: string,
container_username: string,
container_pass: string
container_pass: string,
proxy_username: string,
}

export interface Session {
Expand Down
4 changes: 4 additions & 0 deletions both/schemas/session.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ import SimpleSchema from 'simpl-schema';
import { SessionStatus } from '../models/session.model';

const ContainerSchema = new SimpleSchema({
name : {
type : String,
optional: true
},
container_ip : {
type : String
},
Expand Down
3 changes: 2 additions & 1 deletion client/imports/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { FormsModule } from '@angular/forms';

// Material
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MaterialModule, MdButtonModule, MdListModule, MdInputModule, MdGridListModule, MdDialogModule } from '@angular/material';
import { MaterialModule, MdButtonModule, MdSelectModule, MdListModule, MdInputModule, MdGridListModule, MdDialogModule } from '@angular/material';
import { FlexLayoutModule } from "@angular/flex-layout";

// Imports
Expand Down Expand Up @@ -80,6 +80,7 @@ export const AppRoutes : Routes = [
MdListModule,
MdButtonModule,
MdInputModule,
MdSelectModule,
MdGridListModule,
MdDialogModule,
MarkdownModule.forRoot(),
Expand Down
64 changes: 59 additions & 5 deletions client/imports/lab/lab_terminal.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import * as _ from "lodash";
import { Meteor } from 'meteor/meteor';
import { Tracker } from 'meteor/tracker';
import { Component, ViewChild, ElementRef } from '@angular/core';
import { Component, ViewChild, ElementRef, Input } from '@angular/core';
import { MeteorComponent } from 'angular2-meteor';

// Import Socket.IO
Expand All @@ -25,17 +25,71 @@

// Export LabView Class
export default class LabTerminal extends MeteorComponent {
@ViewChild('terminal') container : ElementRef;
@ViewChild('terminal') terminal_container : ElementRef;
private xterm : Terminal;

@Input('container') container;

constructor() {
super();
XTermStyle;
}

ngOnInit(){
this.xterm = new Terminal();
this.xterm.open(this.container.nativeElement);
this.xterm.fit();
this.xterm = new Terminal({});
}

public bindSocket(){
// Clear Terminal
this.xterm.clear();

// Get URL
var host = this.container.container_ip;

// Create Socket Connection
var socket = io(host, {
'path' : '/xterm/socket.io',
'query' : 'username=' +
this.container.proxy_username +
'&password=' +
this.container.container_pass
});

// Bind to XTerm
socket.on('connect', () => {

// Pass Input
this.xterm.on('data', (data) => {
socket.emit('input', data);
});

// Read Output
socket.on('output', (data) => {
this.xterm.write(data);
}).on('disconnect', (err) => {
console.error(err);
socket.io.reconnection(false);
}).on('exception', (err) => {
console.error(err);
socket.io.reconnection(false);
}).on('error', (err) => {
console.error(err);
socket.io.reconnection(false);
});

// Resize Listener
this.xterm.on('resize', function (size) {
socket.emit('resize', {
cols : size.cols,
rows : size.rows
});
});

// Open Terminal
this.xterm.open(this.terminal_container.nativeElement);
this.xterm.fit();
});

}

}
13 changes: 11 additions & 2 deletions client/imports/lab/lab_view.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,21 @@
<!-- Terminal Component -->
<div>
<md-toolbar>

<md-select placeholder="Machine" *ngIf="(session | async)?.containers?.length > 1" [(ngModel)]="container_index">
<md-option *ngFor="let container of (session | async)?.containers; let i = index" [value]="i">{{ (container)?.name ? container.name : i + 1 }}</md-option>
</md-select>
<span *ngIf="(session | async)?.containers?.length == 1">
{{ (session | async).containers[0]?.name ? (session | async).containers[0].name : LabVM }}
</span>

<span class="spacer"></span>

<button md-icon-button (click)="openConnectionDetails()"><md-icon>dns</md-icon></button>
<button md-icon-button><md-icon>refresh</md-icon></button>
<button md-icon-button (click)="refresh()"><md-icon>refresh</md-icon></button>
</md-toolbar>

<tuxlab-terminal></tuxlab-terminal>
<tuxlab-terminal [container]="containers[container_index]"></tuxlab-terminal>
</div>
</div>

Expand Down
46 changes: 35 additions & 11 deletions client/imports/lab/lab_view.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,39 @@
import { MeteorComponent } from 'angular2-meteor';

// Angular Imports
import { Component, Input } from '@angular/core';
import { Component, Input, ViewChild } from '@angular/core';
import { Router, ActivatedRoute } from "@angular/router";
import { MdDialog } from '@angular/material';
import { ObservableCursor } from 'meteor-rxjs';

// Define Lab View Component
import template from "./lab_view.component.html";
import style from "./lab_view.component.scss";

// Define Dialog Component
import style_dialog from "./lab_view_connection_dialog.scss";
import template_dialog from "./lab_view_connection_dialog.html";
import style from "./lab_view.component.scss";

// Markdown Styles
import prism_style from "prismjs/themes/prism.css";

// Import Lab Data
import { Lab } from '../../../both/models/lab.model';
import { Labs } from '../../../both/collections/lab.collection';
import { Session } from '../../../both/models/session.model';
import { Container, Session } from '../../../both/models/session.model';
import { Sessions } from '../../../both/collections/session.collection';

// Lab Terminal
import LabTerminal from './lab_terminal.component';

// ConnectionDialog Class
@Component({
selector: 'tuxlab-lab-connection-details',
template: template_dialog,
styles: [ style ]
styles: [ style_dialog ]
})
export class ConnectionDetailsDialog extends MeteorComponent {
public session : Observable<Session>;
public container : Container;
}

// LabView Class
Expand All @@ -47,11 +54,17 @@
})

export class LabView extends MeteorComponent {
@ViewChild(LabTerminal) terminal : LabTerminal;

// Data Objects
private lab : Observable<Lab>;
private session : Observable<Session>;

private task_index : number;
private connection_details : any;

private container_index : number = 0;
private containers : Container[];


constructor( private router : Router,
private route: ActivatedRoute,
Expand All @@ -60,8 +73,9 @@
prism_style;
}

ngOnInit(){

// Load Data
ngOnInit(){
// Lab
this.lab = this.route.params
.map(params => [params['course_id'], params['lab_id']])
Expand Down Expand Up @@ -96,10 +110,12 @@
console.log("Connected to Session:");
console.log(res);

// Set Containers and Task Index
this.task_index = res.current_task;
this.connection_details = {
this.containers = res.containers;

};
// Trigger Connection if not Already
this.ngAfterViewInit();

resolve(res);
}
Expand All @@ -109,8 +125,16 @@
});
}

private openConnectionDetails(){
var dialogRef = this.dialog.open(ConnectionDetailsDialog);
private _terminal_init = false;
ngAfterViewInit(){
if(this.terminal && !this._terminal_init){
this.terminal.bindSocket();
this._terminal_init = true;
}
}

private openConnectionDetails(){
var dialogRef = this.dialog.open(ConnectionDetailsDialog, { width: '600px' });
dialogRef.componentInstance.container = this.containers[this.container_index];
}
}
32 changes: 18 additions & 14 deletions client/imports/lab/lab_view_connection_dialog.html
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
<h2> Connection Details </h2>

<p>
In addition to the web terminal here, you can connect to
the Lab using an SSH Client. The connection details are below:
</p>

<table *ngIf="(session | async)">
<tr>
<td> Host: </td>
<td>{{ (session | async)?.containers[0]?.container_ip }}</td>
</tr>
<tr>
<td> Username: </td>
<td>{{ (session | async)?.containers[0]?.container_pass }}</td>
</tr>
<tr>
<td> Password: </td>
<td> {{ (session | async)?.containers[0]?.container_pass }} </td>
</tr>
</table>
<div class="details">
<table>
<tr>
<td> Host: </td>
<td>{{ container.container_ip }}</td>
</tr>
<tr>
<td> Username: </td>
<td>{{ container.proxy_username }}</td>
</tr>
<tr>
<td> Password: </td>
<td> {{ container.container_pass }} </td>
</tr>
</table>
</div>
21 changes: 21 additions & 0 deletions client/imports/lab/lab_view_connection_dialog.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

div.details{
padding: 20px;

background-color: #333;
color:#efefef;

table{
margin:0 auto;

tr{
td{
padding: 5px;

&:first-child{
font-weight: bold;
}
}
}
}
}
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"angular2-meteor-tests-polyfills": "0.0.2",
"babel-runtime": "^6.23.0",
"bcrypt": "^1.0.2",
"bufferutil": "^3.0.2",
"dockerode": "^2.4.3",
"lodash": "^4.17.4",
"meteor-node-stubs": "^0.2.11",
Expand All @@ -52,6 +53,7 @@
"simpl-schema": "^0.1.1",
"socket.io": "^2.0.3",
"uglify-js": "^2.7.5",
"utf-8-validate": "^3.0.3",
"winston": "^2.3.1",
"xterm": "^2.8.1",
"zone.js": "0.8.4"
Expand Down
4 changes: 3 additions & 1 deletion server/imports/api/vmconfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@

/* CONFIGURATION INTERFACE */
export interface VMConfigCustom {
// META
name? : string; // Used to present multiple containers to students

// IMAGE DETAILS
image: string; // Image Name from DockerHub
cmd : string[]; // Entry Command. Defaults to entry.sh

ssh_port: number; // SSH Port

// USER DETAILS
Expand Down
9 changes: 6 additions & 3 deletions server/imports/runtime/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,10 @@
private _container : Dockerode.Container;
public container_id : string;
public container_ip : string;
public proxy_username : string;
public container_dns : string;
public container_username : string;
public container_pass : string;
public proxy_username : string;

constructor(cfg : VMConfig, id? : string){
this.config = VMResolveConfig(cfg);
Expand Down Expand Up @@ -111,11 +112,13 @@
*/
public getJSON() : ContainerModel {
return {
name : this.config.name,
container_ip : this.container_ip,
container_dns : this.container_dns,
container_id : this.container_id,
proxy_username : this.proxy_username,
container_username: this.container_username,
container_pass: this.container_pass
container_pass: this.container_pass,
proxy_username : this.proxy_username,
}
}

Expand Down
Loading

0 comments on commit ab5343b

Please sign in to comment.