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

EC2 SSH key use user data #68

Merged
merged 7 commits into from
Mar 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions ipa/ipa_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@
IPA_HISTORY_FILE = os.path.join(HOME, '.config', 'ipa', '.history')
IPA_RESULTS_PATH = os.path.join(HOME, 'ipa', 'results')

BASH_SSH_SCRIPT = '''#!/bin/bash
echo {key} >> /home/{user}/.ssh/authorized_keys
'''

SYNC_POINTS = (
'test_hard_reboot',
'test_soft_reboot',
Expand Down
28 changes: 20 additions & 8 deletions ipa/ipa_ec2.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

from ipa import ipa_utils
from ipa.ipa_constants import (
BASH_SSH_SCRIPT,
EC2_CONFIG_FILE,
EC2_DEFAULT_TYPE,
EC2_DEFAULT_USER
Expand Down Expand Up @@ -121,7 +122,8 @@ def __init__(self,
)
self.ssh_private_key = (
ssh_private_key or
self._get_from_ec2_config('ssh_private_key')
self._get_from_ec2_config('ssh_private_key') or
self._get_value(ssh_private_key, config_key='ssh_private_key')
)
self.ssh_user = (
ssh_user or
Expand Down Expand Up @@ -228,20 +230,30 @@ def _get_subnet(self, subnet_id):

return subnet

def _get_user_data(self):
"""
Return formatted bash script string.

The public ssh key is added by cloud init to the instance based on
the ssh user and private key file.
"""
key = ipa_utils.generate_public_ssh_key(self.ssh_private_key).decode()
script = BASH_SSH_SCRIPT.format(user=self.ssh_user, key=key)
return script

def _launch_instance(self):
"""Launch an instance of the given image."""
if not self.ssh_key_name:
raise EC2ProviderException(
'SSH Key Name is required to launch an EC2 instance.'
)

kwargs = {
'name': ipa_utils.generate_instance_name('ec2-ipa-test'),
'size': self._get_instance_size(),
'image': self._get_image(),
'ex_keyname': self.ssh_key_name
'image': self._get_image()
}

if self.ssh_key_name:
kwargs['ex_keyname'] = self.ssh_key_name
else:
kwargs['ex_userdata'] = self._get_user_data()

if self.subnet_id:
kwargs['ex_subnet'] = self._get_subnet(self.subnet_id)

Expand Down
2 changes: 1 addition & 1 deletion ipa/scripts/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ def main():
)
@click.option(
'--ssh-key-name',
help='SSH private key file name for EC2.'
help='Optional SSH private key-pair name for EC2.'
)
@click.option(
'--ssh-private-key',
Expand Down
7 changes: 4 additions & 3 deletions man/man1/ipa-list.1
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
.TH "IPA LIST" "1" "27-Feb-2018" "" "ipa list Manual"
.TH "IPA LIST" "1" "20-Mar-2018" "" "ipa list Manual"
.SH NAME
ipa\-list \- Print a list of test files or test cases.
.SH SYNOPSIS
.B ipa list
[OPTIONS] [TEST_DIRS]...
.SH DESCRIPTION
Print a list of test files or test cases.

.PP
If verbose option selected, print all tests cases in
each test file, otherwise print the test files only.

.PP
If test_dirs supplied they will be used to search for
tests otherwise the default test directories are used.
.SH OPTIONS
Expand All @@ -18,3 +18,4 @@ tests otherwise the default test directories are used.
Remove ANSI color and styling from output.
.TP
\fB\-v,\fP \-\-verbose
.PP
13 changes: 7 additions & 6 deletions man/man1/ipa-results.1
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
.TH "IPA RESULTS" "1" "27-Feb-2018" "" "ipa results Manual"
.TH "IPA RESULTS" "1" "20-Mar-2018" "" "ipa results Manual"
.SH NAME
ipa\-results \- Print test results info from provided results...
.SH SYNOPSIS
.B ipa results
[OPTIONS]
.SH DESCRIPTION
Print test results info from provided results json file.

.PP
If no results file is supplied echo results from most recent
test in history if it exists.

.PP
If verbose option selected, echo all test cases.

.PP
If log option selected echo test log.

.PP
If list option is provided echo the results history file.

.PP
If the clear option is provided delete history file.
.SH OPTIONS
.TP
Expand All @@ -41,3 +41,4 @@ The results file or log to parse.
Test result to display.
.TP
\fB\-v,\fP \-\-verbose
.PP
4 changes: 2 additions & 2 deletions man/man1/ipa-test.1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.TH "IPA TEST" "1" "27-Feb-2018" "" "ipa test Manual"
.TH "IPA TEST" "1" "20-Mar-2018" "" "ipa test Manual"
.SH NAME
ipa\-test \- Test image in the given framework using the...
.SH SYNOPSIS
Expand Down Expand Up @@ -72,7 +72,7 @@ EC2 secret access key for login credentials.
GCE service account file for login credentials.
.TP
\fB\-\-ssh\-key\-name\fP TEXT
SSH private key file name for EC2.
Optional SSH private key-pair name for EC2.
.TP
\fB\-\-ssh\-private\-key\fP PATH
SSH private key file for accessing instance.
Expand Down
8 changes: 3 additions & 5 deletions man/man1/ipa.1
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
.TH "IPA" "1" "27-Feb-2018" "" "ipa Manual"
.TH "IPA" "1" "20-Mar-2018" "" "ipa Manual"
.SH NAME
ipa \- Ipa provides a Python API and command line...
.SH SYNOPSIS
.B ipa
[OPTIONS] COMMAND [ARGS]...
.SH DESCRIPTION
Ipa provides a Python API and command line utility for testing images.

.PP
It can be used to test images in the Public Cloud (AWS, Azure, GCE, etc.).
.SH OPTIONS
.TP
Expand All @@ -20,13 +20,11 @@ Show license information and exit.
\fBlist\fP
Print a list of test files or test cases.
See \fBipa-list(1)\fP for full documentation on the \fBlist\fP command.

.PP
\fBresults\fP
Print test results info from provided results...
See \fBipa-results(1)\fP for full documentation on the \fBresults\fP command.

.PP
\fBtest\fP
Test image in the given framework using the...
See \fBipa-test(1)\fP for full documentation on the \fBtest\fP command.
See \fBipa-test(1)\fP for full documentation on the \fBtest\fP command.
31 changes: 15 additions & 16 deletions tests/test_ipa_ec2.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,23 @@ def test_ec2_get_subnet_exception(self, mock_get_driver):

assert msg == str(error.value)

@patch('ipa.ipa_ec2.ipa_utils.generate_public_ssh_key')
def test_ec2_get_user_data(self, mock_generate_ssh_key):
mock_generate_ssh_key.return_value = b'testkey12345'

provider = EC2Provider(**self.kwargs)

result = provider._get_user_data()

assert result == '#!/bin/bash\n' \
'echo testkey12345 >> /home/ec2-user/.ssh/authorized_keys\n'

@patch.object(EC2Provider, '_get_user_data')
@patch.object(EC2Provider, '_get_subnet')
@patch.object(EC2Provider, '_get_driver')
def test_ec2_launch_instance(self, mock_get_driver, mock_get_subnet):
def test_ec2_launch_instance(
self, mock_get_driver, mock_get_subnet, mock_get_user_data
):
"""Test ec2 provider launch instance method."""
driver = MagicMock()

Expand Down Expand Up @@ -164,21 +178,6 @@ def test_ec2_launch_instance(self, mock_get_driver, mock_get_subnet):
assert driver.list_images.call_count == 1
assert driver.create_node.call_count == 1

@patch.object(EC2Provider, '_get_driver')
def test_ec2_launch_no_key_name(self, mock_get_driver):
"""Test ec2 provider raises exception if no ssh key name method."""
driver = MagicMock()
mock_get_driver.return_value = driver

provider = EC2Provider(**self.kwargs)
provider.ssh_key_name = None
msg = 'SSH Key Name is required to launch an EC2 instance.'

with pytest.raises(EC2ProviderException) as error:
provider._launch_instance()

assert str(error.value) == msg

@patch.object(EC2Provider, '_get_driver')
def test_ec2_launch_instance_no_size(self, mock_get_driver):
"""Test exception raised if instance type not found."""
Expand Down