Allow the user to create SSH keys in another term/window, watch for
creation and continue when available.
To test: make check
To QA:
1. Move ~/.ssh to a back up
2. Run quickstart - select w when prompted to watch
3. Create ssh keys as instructed in another term/window
4. Quickstart should continue
5. Move ~/.ssh back; other options should work as expected.
Index: quickstart/app.py
=== modified file 'quickstart/app.py'
--- quickstart/app.py 2013-12-09 18:37:40 +0000
+++ quickstart/app.py 2013-12-13 00:18:27 +0000
@@ -94,25 +94,42 @@
Allow the user to let quickstart create SSH keys, or quit by raising a
ProgramExit if they would like to create the key themselves.
"""
- ssh_dir = os.path.join(os.path.expanduser('~'), '.ssh')
- retcode = utils.call('/usr/bin/find', ssh_dir, '-name', 'id_*.pub')[0]
- if retcode > 0:
+ if check_ssh_keys():
print('No SSH keys were found in ~/.ssh\n\n' 'Would you like quickstart to create them for you? Note
that ' 'this will create a new SSH key with the passphrase you
provide ' 'available to your SSH agent. ssh-keygen will ask for a ' 'passphrase, but juju quickstart will not have access to
it.\n'
- 'Alternatively, you may create the keys on your own.\n')
- create_keys = raw_input('Continue [y/N]? ')
+ 'Alternatively, you may create the keys on your own. '
+ 'Additionally, quickstart can watch for the creation of SSH '
+ 'keys that you create in another terminal or window.\n')
+ create_keys = raw_input('Continue [y/N] or watch for new keys
[w]? ')
if create_keys.lower() == 'y': create_ssh_keys()
+ elif create_keys.lower() == 'w':
+ watch_for_ssh_keys()
else:
- raise ProgramExit('Please run these commands and follow the '
- 'instructions they produce before running '
+ raise ProgramExit('Please run this command and follow the '
+ 'instructions it produces before running ' 'quickstart again:\n\n' 'ssh-keygen -b 4096 -t rsa')
+def check_ssh_keys():
+ ssh_dir = os.path.join(os.path.expanduser('~'), '.ssh')
+ return utils.call('/usr/bin/find', ssh_dir, '-name', 'id_*.pub')[0]
+
+
+def watch_for_ssh_keys():
+ print('Please run this command in another terminal or window and '
+ 'follow the instructions it produces; quickstart will '
+ 'continue when keys are generated. ^C to quit.\n\n'
+ 'ssh-keygen -b 4096 -t rsa\n')
+ while check_ssh_keys() != 0:
+ time.sleep(3)
+ print('.')
+
+
def create_ssh_keys():
"""Create SSH keys for the user
Index: quickstart/tests/test_app.py
=== modified file 'quickstart/tests/test_app.py'
--- quickstart/tests/test_app.py 2013-12-09 18:37:40 +0000
+++ quickstart/tests/test_app.py 2013-12-13 00:18:27 +0000
@@ -187,7 +187,9 @@ 'you provide available to your SSH agent. ssh-keygen
will ' \ 'ask for a passphrase, but juju quickstart will not have '
\ 'access to it.\nAlternatively, you may create the keys
on ' \
- 'your own.\n'
+ 'your own. Additionally, quickstart can watch for the ' \
+ 'creation of SSH keys that you create in another
terminal ' \
+ 'or window.\n'
ssh_key_find = ('/usr/bin/find', os.path.join(os.path.expanduser('~'), '.ssh'), '-name', 'id_*.pub')
@@ -202,8 +204,8 @@ mock_call.assert_called_with(*self.ssh_key_find)
def test_failure_no_keygen(self, mock_print):
- msg = 'Please run these commands and follow the instructions
they ' \
- 'produce before running quickstart again:\n\n' \
+ msg = 'Please run this command and follow the instructions it ' \
+ 'produces before running quickstart again:\n\n' \ 'ssh-keygen -b 4096 -t rsa'
with self.assert_program_exit(msg):
with self.patch_call(130) as mock_call:
@@ -224,6 +226,39 @@ self.assertTrue(mock_raw_input.called) self.assertTrue(mock_create_ssh_keys.called)
+ def test_failure_with_watch(self, mock_print):
+ with self.patch_call(130) as mock_call:
+ with self.patch_raw_input(return_value='W') as mock_raw_input:
+ with mock.patch('quickstart.app.watch_for_ssh_keys') \
+ as mock_watch_for_ssh_keys:
+ app.ensure_ssh_keys()
+ mock_call.assert_called_with(*self.ssh_key_find)
+ mock_print.assert_has_calls([mock.call(self.print_msg)])
+ self.assertTrue(mock_raw_input.called)
+ self.assertTrue(mock_watch_for_ssh_keys.called)
+
+
+class TestWatchForSSHKeys(helpers.CallTestsMixin, unittest.TestCase):
+
+ @mock.patch('time.sleep')
+ @helpers.mock_print
+ def test_watch(self, mock_print, mock_sleep):
+ side_effects = (
+ (130, '', ''),
+ (0, '', ''),
+ )
+ with self.patch_multiple_calls(side_effects):
+ app.watch_for_ssh_keys()
+ mock_print.assert_has_calls([
+ mock.call('Please run this command in another terminal or
window '
+ 'and follow the instructions it produces;
quickstart '
+ 'will continue when keys are generated. ^C to
quit.\n\n'
+ 'ssh-keygen -b 4096 -t rsa\n'),
+ mock.call('.')
+ ])
+ mock_sleep.assert_called_once_with(3)
+ mock_print.assert_called_with('.')
+
Reviewers: mp+198851_ code.launchpad. net,
Message:
Please take a look.
Description:
Watch for SSH key creation
Allow the user to create SSH keys in another term/window, watch for
creation and continue when available.
To test: make check
To QA:
1. Move ~/.ssh to a back up
2. Run quickstart - select w when prompted to watch
3. Create ssh keys as instructed in another term/window
4. Quickstart should continue
5. Move ~/.ssh back; other options should work as expected.
https:/ /code.launchpad .net/~makyo/ juju-quickstart /ssh-3- watch-keys/ +merge/ 198851
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/39610049/
Affected files (+64, -10 lines): tests/test_ app.py
A [revision details]
M quickstart/app.py
M quickstart/
Index: [revision details]
=== added file '[revision details]'
--- [revision details] 2012-01-01 00:00:00 +0000
+++ [revision details] 2012-01-01 00:00:00 +0000
@@ -0,0 +1,2 @@
+Old revision:
<email address hidden>
+New revision: <email address hidden>
Index: quickstart/app.py join(os. path.expanduser ('~'), '.ssh') '/usr/bin/ find', ssh_dir, '-name', 'id_*.pub')[0]
'Would you like quickstart to create them for you? Note
'this will create a new SSH key with the passphrase you
'available to your SSH agent. ssh-keygen will ask for a '
'passphrase, but juju quickstart will not have access to
create_ ssh_keys( ) ssh_keys( )
'quickstart again:\n\n'
'ssh- keygen -b 4096 -t rsa')
=== modified file 'quickstart/app.py'
--- quickstart/app.py 2013-12-09 18:37:40 +0000
+++ quickstart/app.py 2013-12-13 00:18:27 +0000
@@ -94,25 +94,42 @@
Allow the user to let quickstart create SSH keys, or quit by raising a
ProgramExit if they would like to create the key themselves.
"""
- ssh_dir = os.path.
- retcode = utils.call(
- if retcode > 0:
+ if check_ssh_keys():
print('No SSH keys were found in ~/.ssh\n\n'
that '
provide '
it.\n'
- 'Alternatively, you may create the keys on your own.\n')
- create_keys = raw_input('Continue [y/N]? ')
+ 'Alternatively, you may create the keys on your own. '
+ 'Additionally, quickstart can watch for the creation of SSH '
+ 'keys that you create in another terminal or window.\n')
+ create_keys = raw_input('Continue [y/N] or watch for new keys
[w]? ')
if create_keys.lower() == 'y':
+ elif create_keys.lower() == 'w':
+ watch_for_
else:
- raise ProgramExit('Please run these commands and follow the '
- 'instructions they produce before running '
+ raise ProgramExit('Please run this command and follow the '
+ 'instructions it produces before running '
+def check_ssh_keys(): join(os. path.expanduser ('~'), '.ssh') '/usr/bin/ find', ssh_dir, '-name', 'id_*.pub')[0] ssh_keys( ):
+ ssh_dir = os.path.
+ return utils.call(
+
+
+def watch_for_
+ print('Please run this command in another terminal or window and '
+ 'follow the instructions it produces; quickstart will '
+ 'continue when keys are generated. ^C to quit.\n\n'
+ 'ssh-keygen -b 4096 -t rsa\n')
+ while check_ssh_keys() != 0:
+ time.sleep(3)
+ print('.')
+
+
def create_ssh_keys():
"""Create SSH keys for the user
Index: quickstart/ tests/test_ app.py tests/test_ app.py' tests/test_ app.py 2013-12-09 18:37:40 +0000 tests/test_ app.py 2013-12-13 00:18:27 +0000
'you provide available to your SSH agent. ssh-keygen
'ask for a passphrase, but juju quickstart will not have '
'access to it.\nAlternatively, you may create the keys
os.path. join(os. path.expanduser ('~'), '.ssh'),
'-name' , 'id_*.pub')
mock_ call.assert_ called_ with(*self. ssh_key_ find)
=== modified file 'quickstart/
--- quickstart/
+++ quickstart/
@@ -187,7 +187,9 @@
will ' \
\
on ' \
- 'your own.\n'
+ 'your own. Additionally, quickstart can watch for the ' \
+ 'creation of SSH keys that you create in another
terminal ' \
+ 'or window.\n'
ssh_key_find = ('/usr/bin/find',
@@ -202,8 +204,8 @@
def test_failure_ no_keygen( self, mock_print):
'ssh- keygen -b 4096 -t rsa' program_ exit(msg) : call(130) as mock_call:
self. assertTrue( mock_raw_ input.called)
self. assertTrue( mock_create_ ssh_keys. called)
- msg = 'Please run these commands and follow the instructions
they ' \
- 'produce before running quickstart again:\n\n' \
+ msg = 'Please run this command and follow the instructions it ' \
+ 'produces before running quickstart again:\n\n' \
with self.assert_
with self.patch_
@@ -224,6 +226,39 @@
+ def test_failure_ with_watch( self, mock_print): call(130) as mock_call: raw_input( return_ value=' W') as mock_raw_input: 'quickstart. app.watch_ for_ssh_ keys') \ for_ssh_ keys: ssh_keys( ) assert_ called_ with(*self. ssh_key_ find) assert_ has_calls( [mock.call( self.print_ msg)]) (mock_raw_ input.called) (mock_watch_ for_ssh_ keys.called) Keys(helpers. CallTestsMixin, unittest.TestCase): 'time.sleep' ) multiple_ calls(side_ effects) : for_ssh_ keys() assert_ has_calls( [ assert_ called_ once_with( 3) assert_ called_ with('. ')
+ with self.patch_
+ with self.patch_
+ with mock.patch(
+ as mock_watch_
+ app.ensure_
+ mock_call.
+ mock_print.
+ self.assertTrue
+ self.assertTrue
+
+
+class TestWatchForSSH
+
+ @mock.patch(
+ @helpers.mock_print
+ def test_watch(self, mock_print, mock_sleep):
+ side_effects = (
+ (130, '', ''),
+ (0, '', ''),
+ )
+ with self.patch_
+ app.watch_
+ mock_print.
+ mock.call('Please run this command in another terminal or
window '
+ 'and follow the instructions it produces;
quickstart '
+ 'will continue when keys are generated. ^C to
quit.\n\n'
+ 'ssh-keygen -b 4096 -t rsa\n'),
+ mock.call('.')
+ ])
+ mock_sleep.
+ mock_print.
+
@helpers. mock_print
class TestCreateSSHKeys(