Skip to content
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

T2 root #290

Closed
wants to merge 43 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
5b740e4
Travis containers added
Student007 Jul 31, 2015
ec33032
Update .travis.yml
Student007 Jul 31, 2015
e6a8b58
Travis-CI containers
Student007 Jul 31, 2015
fe72e82
apt-get fix for Travis-CI
Student007 Jul 31, 2015
32611c0
docs confuse me
Student007 Jul 31, 2015
7aaf6ad
...
Student007 Jul 31, 2015
4d82d6e
..
Student007 Jul 31, 2015
c592d9c
,,
Student007 Jul 31, 2015
61b1042
m
Student007 Jul 31, 2015
70c8002
a
Student007 Jul 31, 2015
4391bdd
a
Student007 Jul 31, 2015
f262fc8
s
Student007 Jul 31, 2015
ef36e92
wrappy
Student007 Jul 31, 2015
9c1e15d
s
Student007 Jul 31, 2015
2c0c982
q
Student007 Jul 31, 2015
95a71da
require sudo
Student007 Jul 31, 2015
e680cbc
newline
Student007 Jul 31, 2015
e8dc023
reset to initial version
Student007 Jul 31, 2015
c76a849
Travis-CI Image to Student007
Student007 Jul 31, 2015
9860c3d
Revert "Travis-CI Image to Student007"
Student007 Jul 31, 2015
71a2820
first clean version of "t2 root"
Student007 Jul 31, 2015
24d3120
stupid mindless mistake fixed
Student007 Jul 31, 2015
f69d51a
travis test fails for linting
Student007 Jul 31, 2015
c3da285
wrapper exact version
Student007 Jul 31, 2015
370e1f7
linting done
Student007 Aug 1, 2015
eb7346e
I hate the NEWLINE rule of JSCS
Student007 Aug 1, 2015
a6d5551
Travis-CI is more restrictive ?
Student007 Aug 1, 2015
9424ce0
grunt test --force changes this each run for some reason
Student007 Aug 2, 2015
4c3ed3b
clean up dependencies
Student007 Aug 2, 2015
804d493
Tessel.seekTessels unit tests
Student007 Aug 12, 2015
67ff671
removed copy paste comments
Student007 Aug 12, 2015
2e2334f
need workaround for VM tests
Student007 Aug 14, 2015
3fbe20c
VM without USB relevant handling!
Student007 Aug 15, 2015
99f3c43
Cleaning up user messages style
Student007 Aug 15, 2015
0fa8ba8
controller.root test no 1
Student007 Sep 3, 2015
3056a6c
modulize controller.ssh
Student007 Sep 9, 2015
a879c67
accidentally pushed the commit button... sorry for no comments
Student007 Sep 9, 2015
2cb829b
mixed up reject and resolve usage ;-)
Student007 Sep 9, 2015
6f6dbff
Solving Windows related hostname resolution bug
Student007 Sep 9, 2015
17e0914
not necessary
Student007 Sep 9, 2015
b882da5
not my work (copied for testing)
Student007 Sep 9, 2015
eb50c0f
logs.error isn't known so changed to logs.warn
Student007 Sep 9, 2015
cdd15b2
due to editing usb_connection tests need to change
Student007 Sep 9, 2015
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 30 additions & 0 deletions bin/tessel-2.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,36 @@ parser.command('rename')
.help('Change the name of a Tessel to something new.');


// accessing the root shell of your tessels
// Fixes issue https://github.com/tessel/t2-cli/issues/80
/**
$ t2 root --help
> Usage: tessel root [-i <path>] [--help]
> -i <path>: provide a path to the desired ssh key
$

$ t2 root
> Accessing root...
root@192.168.128.124 #
*/
var default_id_rsa = '~/.tessel/id_rsa';
var functional_msg = '\nGain SSH root access to one of your authorized tessels (menu listing if multiple targets)';
parser.command('root')
.usage(functional_msg + '\n\nUsage: t2 root [-i PATH] [--help]\n\n-i PATH: Optional targeting a different Private Key \n\n(Note: default target created by "t2 key generate" is ' + default_id_rsa + ')\n')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@johnnyman727 eventually we're going to need to put these icky strings into template files and load them in at runtime

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Student007 there is no need to add the usage function here. nomnom takes care of it for you as long as you add help tags to all the parameters. Check out the other commands for an example.

@rwaldron ugh agreed!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is, it would write Usage: node t2 root instead of t2 root - I like the idea of templates.
@Frijol it looks like you are figuring out some things at #274 - is there also a general way to fix the node t2 root problem ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I have:

parser.command('root')
  .option('path', {
    abbr: 'i',
    full: 'path',
    metavar: 'PATH',
    default: '~/.tessel/id_rsa',
    help: 'Private Key (Note: created by "t2 key generate")'
  })
  .callback(function(opts) {
    controller.root(opts)
      .then(closeSuccessfulCommand, closeFailedCommand);
  })
  .help('Gain SSH root access to one of your authorized tessels (menu listing if multiple targets)');

I get:

➜  t2-cli git:(t2-root) ✗ t2 root -h

Usage: /usr/local/bin/iojs t2 root [options]

Options:
   -i PATH, --path PATH   Private Key (Note: created by "t2 key generate")  [~/.tessel/id_rsa]

Gain SSH root access to one of your authorized tessels (menu listing if multiple targets)

What's the issue? You want to get rid of /usr/local/bin/iojs part?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Frijol yes 😄

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what would be a new issue / contribution task

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see. Yeah, that should be a separate issue. Good idea. A brief look through nomnom.js doesn't reveal a solution.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I couldn't find a provided solution in nomnom.js ... also reading code ... did this before some weeks)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Student007 what do you think about leaving the usage string our for this PR and then we'll make a separate PR that grabs all strings from a template file. I'd rather keep them all consistent at any one time so that it's more straightforward for new contributors.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since 6 days Nomnom is deprecated !

I've figured out ... and created a pull request:
#310
The reason I though it doesn't work was to use the "script" part on on the wrong object level.

.option('path', {
abbr: 'i',
full: 'path',
metavar: 'PATH',
default: default_id_rsa,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Student007 this path is already used in another part of the codebase (probably lan_connection.js). We should have this defined in only one place that's accessible to both files.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@johnnyman727 it is:

Tessel is included in provision.js and also lan_connection.js but useless in bin/tessel-2.js!
The only solution would be to use controller.js to provide that const because controller.js is included within bin/tessel-2.js. A possible solution could be:

controller.TESSEL_AUTH_KEY = Tessel.TESSEL_AUTH_PATH+'/id_rsa';

within controller.js

That way I would replace default: default_id_rsa by controller.TESSEL_AUTH_KEY

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Student007 I think it makes the most sense for the path to live in provision.js since that file is responsible for creating the keys. Could you export the path from provision.js and import the path in lan_connection.js and tessel-2.js?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@johnnyman727 you mean changing bin/tessel-2.js by adding

default: require(../lib/tessel/provision.js).TESSEL_AUTH_KEY,

after changing provision.js like

module.exports.TESSEL_AUTH_KEY = filepath;

help: 'Private Key (Note: created by "t2 key generate")'
})
.callback(function(opts) {
controller.root(opts)
.then(closeSuccessfulCommand, closeFailedCommand);
})
.help(functional_msg);


module.exports = function(args) {
parser.parse(args);
};
Expand Down
144 changes: 139 additions & 5 deletions lib/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ var sprintf = require('sprintf-js').sprintf;
var cp = require('child_process');
var async = require('async');
var controller = {};
controller.ssh = require('./root_controller');
var Menu = require('terminal-menu');
var networkInterfaces = require('os').networkInterfaces();
var debug = require('debug')('controller');

Tessel.list = function(opts) {

Expand All @@ -22,21 +26,22 @@ Tessel.list = function(opts) {
// When a Tessel is found
seeker.on('tessel', function displayResults(tessel) {
var note = '';

// Add it to our array
foundTessels.push(tessel);

// Add a note if the user isn't authorized to use it yet
if (tessel.connection.connectionType === 'LAN' && !tessel.connection.authorized) {
note = '(USB connect and run `tessel provision` to authorize)';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you remove these unrelated styling changes?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@johnnyman727 yes I did many times (also at other code parts) but the linter automatically edited this many times. So I gave up to do this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Student007 did it only do this when you ran with -force?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also grunt test if I remember right. But last pull requests and after forking branches from tessel/master the problem doesn't come up anymore 👍

}

// Print out details...
logs.basic(sprintf('\t%s\t%s\t%s', tessel.name, tessel.connection.connectionType, note));
});

// Called after CTRL+C or timeout
function stopSearch() {
if (foundTessels.length > 1) {
debug('heuristics ? => found: ' + foundTessels.length + ' === 1 || (' + foundTessels.length + ' === 2 && ' + foundTessels[0].name + ' === ' + foundTessels[1].name + ' && ' + foundTessels[0].connections[0].connectionType + ' !== ' + foundTessels[1].connections[0].connectionType + ')');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Student007 what is this debug line for?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@johnnyman727 it was related to debug network topology behaviors. I used it for my own but decided to keep it in because some people do not know they will find their Tessel twice due to network topology. A simple case I would expect lots of time is a iMac is connected by LAN and WLAN to the same router for different development reasons like multi IP services. Of cause people who do this, know it, but ... they will forgot it and need to be pointed on while contributing to Tessel...
But of cause I can remove it - it is not well formed anyway.
Shall I remove it or change it ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Student007 I think we should remove it and add infrastructure to controller.list to weed out duplicates (which can be a separate PR later).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I am currently working on that feature in Tessel.list. At the moment I got crazy about sometimes there are objects with tessel.connection and sometimes tessel.connections my current workaround (not shown here and public) is causing secondary errors. I am still figuring out this and that line helped me. But of cause it will be away later - it has no usage for developing apps ...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Student007 I don't think you need to worry about the number of connections for a Tessel. You can just check the lanConnection object: https://github.com/tessel/t2-cli/blob/master/lib/tessel/tessel.js#L13

That should give you the name and even ip address of the Tessel.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes ... that was new ... ;)


}
// If the seeker exists (it should)
if (seeker !== undefined) {
// Stop looking for more Tessels
Expand All @@ -54,8 +59,10 @@ Tessel.list = function(opts) {
}
// If we have only one Tessel or two Tessels with the same name (just USB and LAN)
else if (foundTessels.length === 1 ||
(foundTessels.length === 2 && foundTessels[0].name === foundTessels[1].name)) {
(foundTessels.length === 2 && foundTessels[0].name === foundTessels[1].name && foundTessels[0].connections[0].connectionType !== foundTessels[1].connections[0].connectionType)) {
// Close all opened connections and resolve
console.log(foundTessels[0].connections.connectionType);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Student007 can you remove these console.logs?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh -- of cause ... don't know why I didn't see this

console.log(foundTessels[1].connections.connectionType);
controller.closeTesselConnections(foundTessels)
.then(resolve);
}
Expand Down Expand Up @@ -170,6 +177,134 @@ Tessel.get = function(opts) {
}
});
};
/*
Because of sync problem with master trunk and parallel development on Tessel.list
it was necessary to go my own way...
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just pull & rebase as development proceeded?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Student007 do you need some assistance rebasing this commit on master? How can we take advantage of the work that was done on master while you were working on this? What of this new code can we remove?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally, we should remove the entire seek method because this functionality is in master.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, if the logAndFinish got a menu and returns the selected Tessel (or set the process.env.TESSEL) the controller.ssh.seek(opts) could be replaced by Tessel.get(opts) in controller.root - I have to take a look at Tessel.get I am currently not familiar how it works like (comming soon ;) ).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tessel.get essentially scans for all Tessels (just like Tessel.list) and then runs the found Tessels through a bunch of heuristics to determine which one the user likely wants. It can be considered a black box where you always get the Tessel the user would like to operate on.


The seekTessels method never uses heuristics because all possible login variants are required.
There is a new feature in: In the case your network topology causes a Tessels IP is found twice, the
menu will only list it once.

Due to my own stupid failing with mixing up a tessel is accessable via gateway and a Tessel is in the
same Netmask, I've added a notice for the case someone run into same issue.
*/
Tessel.seekTessels = function(opts) {
return new Promise(function(resolve, reject) {

if (opts.timeout && typeof opts.timeout === 'number') {
// Stop the search after that duration
setTimeout(stopSeeker, opts.timeout * 1000);
} else {
// default to 3 seconds searching
setTimeout(stopSeeker, 3000);
}
logs.info('Searching accessable Tessels ...');

var seeker = new discover.TesselSeeker().start();
var tessels = [];

// When we find Tessels
seeker.on('tessel', function(tessel) {
controller.closeTesselConnections(tessel)
.then(function() {
var known = false;
if (tessels.length >= 1) {
for (var i in tessels) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use for-in to iterate arrays, use either regular for loop or tessels.forEach

if (tessel.connections[0].ip === tessels[i].connections[0].ip && tessel.connections[0].connectionType === 'LAN') {
// Your network topology causes a single tessel is found twice
debug('known = true');
known = true;
}
}

}
if (known) {
debug('Due to your Network-Topology ' + tessel.name + ' is found twice! (' + tessel.connections[0].ip + ')');
} else {
// Add it to our array
tessels.push(tessel);
}
});
});

seeker.on('error', function(e) {
reject(e);
});

function stopSeeker() {
try {
// If there were no Tessels found
if (!tessels || tessels.length === 0) {
// Report the sadness
debug('We are searching the following networks:\n', networkInterfaces);
debug('\n(Important: Check your Netmask - we do not follow gateways for discovering!)');
logs.warn('No Tessels found (DEBUG=controller t2 root # might help!)');
resolve();
}
seeker.stop();
seeker = null; // preventing memory leaks
return resolve(tessels);
} catch (e) {
reject(e);
}
}
});
};
/*
The T2 root command is used to login into the firmware and gaining superuser access.
The security is provided by RSA - your Tessel get the keys while provisioning via USB.

If you have only one Tessel, the T2 root command will login directly else there is
a ncurses like menu you can select the Tessel you like to gain root access...

The structure of code and maybe unusual parts are paid due being testable.
The lightweight terminal-menu isn't written testable what needs a little bit hacking.

Finally some parts are causing from my personnal learning curve about writing unit tests using sinon!
*/
controller.root = function(opts) {
// ~ conversion to home because spawn isn't able to handle this right
if (opts.path && opts.path.substring(0, 1) === '~') {
var home = process.env.HOME;
opts.path = opts.path.replace('~', home);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will break if there is a ~ anywhere else in the path.

rwaldron at new-host-3 in ~
$ mkdir -p foo/ba~r/baz
rwaldron at new-host-3 in ~
$ cd foo/
rwaldron at new-host-3 in ~/foo
$ ls
.
└── [drwxr-xr-x rwaldron staff     102 Sep  9 12:52]  ba~r/

1 directory, 0 files
rwaldron at new-host-3 in ~/foo
$ cd ba~r/
rwaldron at new-host-3 in ~/foo/ba~r
$ ls
.
└── [drwxr-xr-x rwaldron staff      68 Sep  9 12:52]  baz/

1 directory, 0 files
rwaldron at new-host-3 in ~/foo/ba~r
$ cd baz/
rwaldron at new-host-3 in ~/foo/ba~r/baz
$ ls
.

0 directories, 0 files

Please use the method shown here: https://github.com/tessel/t2-cli/blob/master/lib/tessel/deploy.js#L105-L123

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rwaldron ... you are right. I didn't expect someone would use ~ in a different way ...

}
var rtm;
if (!opts.menu) {
// TODO: Tessel cooperate identity conform menu required (color, ascii logo)
rtm = Menu({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Student007 we should pull the menu out of this PR, and place it into another PR where it can pop up a menu when any command is run and there is ambiguity about which T2 is the "right T2. In fact, it would fix another long standing issue, #235.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@johnnyman727 I am currently working on this #235 and created a branch menu and list ...
Looks like I have to make controller.ssh reusable (and give it a better name or divide it int o .ssh and .menu) 😉 but I will not get it done today.
If I understand it right, Tessel.list the Menu select event listener should set process.env.TESSEL to the selected tessel.name ? That way the next run would use it. Or maybe the provision needs to read the process.env.TESSEL somewhere additional ...
(I am out of time for today)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@johnnyman727 setting process.env.TESSEL isn't possible to be set for next call of t2 list.
(maybe it would be by fs open and change profile on different operating systems ... but this would be an other task/issue).

So it will simple keep the menu is opened for setting the default Tessel to work with.

An other idea would be a .tessel/defaultTessel.tmp with the tessel.name in it ?!

The controller.js code doesn't show something about where and how you are using the selected Tessel. Heuristics only return one Tessel and logs.info is talking about...
I need to know the plan about this 😄

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand it right, Tessel.list the Menu select event listener should set process.env.TESSEL to the selected tessel.name ?

A menu for selecting a Tessel should only be used with Tessel.get, not Tessel.list. Listing shows all available Tessels so there is no need to select one at that time. Let me know if that doesn't make sense.

An other idea would be a .tessel/defaultTessel.tmp with the tessel.name in it ?!

@Student007 I don't recommend storing state in a file across CLI calls because things can get hairy if you run two commands at once or another program is using the CLI API. In the latter case, you could have two processes writing to the file at the same time.

When logAndFinish get called after the search for a Tessel, if no tessel is passed in as the arg, it means multiple possible Tessels were found and this is where users should be able to select which they'd prefer. We should also print out a message that indicates that they can use the --name flag to avoid the manual selection process.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK like current idea of logSelected but moved to logAndFinish else {...} (btw: the new Menu is moved to prepareMenu)

@Student007 I don't recommend storing state in a file across CLI calls because things can get hairy if you run two commands at once or another program is using the CLI API. In the latter case, you could have two processes writing to the file at the same time.

You are right. But in this special case it overrides the file when the user is doing interaction. Another process what overrides the file would fail the same way two terminals try to pipe data into one file or do other stuff with the same target.

I think it is the only useful way to fix a special Tessel to work with. I think there would be cases a developer will have e.g. 8 Tessels with different apps what should work together and he likes to select the current one without typing every time. He would use t2 list and select one.

Another idea would be a new command t2 select what will show the menu to fix the Tessel to work with. Because it isn't possible to export process.env.TESSEL outside the running process, the only idea is to use a ~/.tesse./selectedTessel.log (with the risk of other developers will hack around: My current non published version is checking whether the written name is matching an existing Tessel).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the case where a user has several Tessels they are trying to work with, they could more easily set a different TESSEL env variable in a shell for each one. That way they don't have to manually interact - it would automatically select the proper Tessel. Once you open a separate PR for Tessel selection, we can continue the discussion there.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@johnnyman727 I still didn't think about this from that point of view. You are right, if someone opens several terminals (one for each Tessel 2) the ~/.tesse./selectedTessel.logidea isn't the right solution.
On the other hand a possible t2 select command will not work, because I don't know a way to set process.env.TESSEL out of Node.js/t2-cli to stay selected after running the command.
Maybe a possible solution could be to add the PID to the log-name and remove all log-names by t2-cli when the PID isn't alive anymore when running the t2-cli next time.
That way it would work to create a t2 select command with the goal to prevent the non-familiar way (to many non hackers).
If you would agree I will create that pull request.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@johnnyman727 based on this ideas I am preparing an additional pull request, but I am not done at the moment.

What will be in:

  • makeCommand('select')
  • Tessel.seekTessels() -> returns list of found Tessels asynchronously!
  • controller.ssh.checkAuthorized() asynchronously!
  • testSSHConnection() asynchronously!
  • getAuthorizedTessels() with async.forEachOf(tessels, testSSHConnection) asynchronously!
  • getTerminalsPID() process.platform based asynchronously!
  • checkPIDexists(pid) process.platform based asynchronously!
  • checkAllPIDfiles() process.platform based asynchronously!
  • createSelectedTesselPIDfile(pid) asynchronously!
  • checkAllPIDfiles() fs.readdirAsync & fs.readFileAsync asynchronously!
  • set process.env.Tessel
  • get global id_rsa
  • let it work with menu pull request
var authorizedTessels = [];
    if (opts.name) {
      // if name selected test if authorized
      testSSHConnection()
      .getTerminalsPID()
      .checkAllPIDfiles()
      .createSelectedTesselPIDfile();
      //.catch()
    } else {
      getTerminalsPID()
      .checkAllPIDfiles()
      .getAuthorizedTessels(function(tessels) {
        if(tessels.length === 0) {
          // no authorized Tessels
          reject('No authorized Tessels found!');
        } else if (tessels.length === 1) {
          // select direct
          createSelectedTesselPIDfile();
        } else {
          // menu
          controller.menu.prepare(tessels)
          .createSelectedTesselPIDfile();
        }
      })
      .controller.menu.prepare()
      .createSelectedTesselPIDfile();
    }

width: 50,
x: 1,
y: 2,
bg: 'red'
});
} else {
// used while testing to override methods by stubs (testing doesn't like user interactions)
rtm = opts.menu;
}
return new Promise(function(resolve, reject) {
controller.ssh.seek(opts)
.then(function(tessels) {

if (tessels && tessels.length >= 2) {
controller.ssh.multipleTessels(opts, tessels, rtm, resolve, reject);
} else if (tessels && tessels.length === 1) {
if (tessels[0].connection.authorized) {
controller.ssh.runSSH(0, opts, tessels, resolve, reject);
} else {
logs.warn('Sorry, you are not authorized!');
logs.info('"t2 key generate" might help :-)');
resolve();
}
} else {
// everything works fine, but no tessels found
resolve();
}

}).catch(function(e) {
reject(e);
});
});
};

/*
Takes a list of Tessels with connections that
Expand Down Expand Up @@ -451,7 +586,6 @@ controller.connectToNetwork = function(opts) {
});
});
};

module.exports = controller;

// Shared exports
Expand Down