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

Add inject option for ipa testing. #78

Merged
merged 2 commits into from
May 15, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 2 additions & 0 deletions ipa/ipa_azure.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def __init__(self,
early_exit=None,
history_log=None,
image_id=None,
inject=None,
instance_type=None,
log_level=30,
no_default_test_dirs=False,
Expand All @@ -72,6 +73,7 @@ def __init__(self,
early_exit,
history_log,
image_id,
inject,
instance_type,
log_level,
no_default_test_dirs,
Expand Down
2 changes: 2 additions & 0 deletions ipa/ipa_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def test_image(provider_name,
early_exit=None,
history_log=None,
image_id=None,
inject=None,
instance_type=None,
log_level=None,
no_default_test_dirs=None,
Expand Down Expand Up @@ -83,6 +84,7 @@ def test_image(provider_name,
early_exit=early_exit,
history_log=history_log,
image_id=image_id,
inject=inject,
instance_type=instance_type,
log_level=log_level,
no_default_test_dirs=no_default_test_dirs,
Expand Down
2 changes: 2 additions & 0 deletions ipa/ipa_ec2.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def __init__(self,
early_exit=None,
history_log=None,
image_id=None,
inject=None,
instance_type=None,
log_level=30,
no_default_test_dirs=False,
Expand Down Expand Up @@ -75,6 +76,7 @@ def __init__(self,
early_exit,
history_log,
image_id,
inject,
instance_type,
log_level,
no_default_test_dirs,
Expand Down
2 changes: 2 additions & 0 deletions ipa/ipa_gce.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ def __init__(self,
early_exit=None,
history_log=None,
image_id=None,
inject=None,
instance_type=None,
log_level=30,
no_default_test_dirs=False,
Expand All @@ -75,6 +76,7 @@ def __init__(self,
early_exit,
history_log,
image_id,
inject,
instance_type,
log_level,
no_default_test_dirs,
Expand Down
70 changes: 70 additions & 0 deletions ipa/ipa_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ def __init__(self,
early_exit=None,
history_log=None,
image_id=None,
inject=None,
instance_type=None,
log_level=None,
no_default_test_dirs=False,
Expand Down Expand Up @@ -102,6 +103,7 @@ def __init__(self,
self.distro_name = self._get_value(distro_name)
self.early_exit = self._get_value(early_exit)
self.image_id = self._get_value(image_id)
self.inject = self._get_value(inject)
self.instance_type = self._get_value(instance_type)
self.running_instance_id = self._get_value(running_instance_id)
self.test_files = list(self._get_value(test_files, default=[]))
Expand Down Expand Up @@ -447,6 +449,71 @@ def install_package(self, client, package):
log_file.write('\n')
log_file.write(out)

def process_injection_file(self, client):
"""
Load yaml file and process injection configuration.
There are 5 injection options:
:inject_packages: an rpm path or list of rpm paths which will be
copied and installed on instance.
Copy link
Collaborator

Choose a reason for hiding this comment

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

... installed on the test instance.

:inject_archives: an archive or list of archives which will
be copied and extracted on instance.
Copy link
Collaborator

Choose a reason for hiding this comment

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

dito

:inject_files: a file path or list of file paths which
will be copied to instance.
Copy link
Collaborator

Choose a reason for hiding this comment

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

dito

:execute: a command or list of commands to run.
:install: a package name or list of package names to
install from an existing repo.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please add the order of processing to the doc string

"""
configuration = ipa_utils.get_yaml_config(self.inject)

if configuration.get('inject_packages'):
inject_packages = configuration['inject_packages']

if not isinstance(inject_packages, list):
inject_packages = [inject_packages]

for package in inject_packages:
package_path = self.put_file(client, package)
self.install_package(client, package_path)

if configuration.get('inject_archives'):
inject_archives = configuration['inject_archives']

if not isinstance(inject_archives, list):
inject_archives = [inject_archives]

for archive in inject_archives:
archive_path = self.put_file(client, archive)
self.extract_archive(client, archive_path)

if configuration.get('inject_files'):
inject_files = configuration['inject_files']

if not isinstance(inject_files, list):
inject_files = [inject_files]

for file_path in inject_files:
self.put_file(client, file_path)
Copy link
Collaborator

Choose a reason for hiding this comment

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

One could, and some people will argue that packages and tar archives are files as well. I am OK leaving this option as if one want to inject a config file that effects a package forcing them to create an archive is silly and it saves us the logic of having to determine file types for certain operation.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah "put" is the first step to injecting a package and an archive. So exposing it independently I think is nice. I.e. like your example to copy a single file.


if configuration.get('execute'):
execute = configuration['execute']

if not isinstance(execute, list):
execute = [execute]

for command in execute:
self.execute_ssh_command(client, command)

if configuration.get('install'):
install = configuration['install']

if not isinstance(install, list):
install = [install]

for package in install:
self.install_package(client, package)

def put_file(self, client, source_file):
"""
Put file on instance in default SSH directory.
Expand Down Expand Up @@ -507,6 +574,9 @@ def test_image(self):
self._set_distro()
self._log_info()

if self.inject:
self.process_injection_file(self._get_ssh_client())

status = 0
with ipa_utils.ssh_config(self.ssh_user, self.ssh_private_key)\
as ssh_config:
Expand Down
7 changes: 7 additions & 0 deletions ipa/scripts/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@ def main(context, no_color):
'--image-id',
help='The ID of the image used for instance.'
)
@click.option(
'--inject',
help='Path to an injection yaml config file.',
type=click.Path(exists=True)
)
@click.option(
'-t',
'--instance-type',
Expand Down Expand Up @@ -228,6 +233,7 @@ def test(context,
early_exit,
history_log,
image_id,
inject,
instance_type,
log_level,
no_default_test_dirs,
Expand Down Expand Up @@ -260,6 +266,7 @@ def test(context,
early_exit,
history_log,
image_id,
inject,
instance_type,
log_level,
no_default_test_dirs,
Expand Down
5 changes: 5 additions & 0 deletions tests/data/injection/test_injection.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
inject_packages: /home/user/test.noarch.rpm
inject_archives: /home/user/test.tar.xz
install: python3
inject_files: /home/user/test.py
execute: python test.py
38 changes: 38 additions & 0 deletions tests/test_ipa_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,44 @@ def test_provider_install_package(self):
call('package install successful!')
])

@patch.object(IpaProvider, 'execute_ssh_command')
@patch.object(IpaProvider, 'extract_archive')
@patch.object(IpaProvider, 'install_package')
@patch.object(IpaProvider, 'put_file')
def test_process_injection_file(self,
mock_put_file,
mock_install_package,
mock_extract_archive,
mock_execute_command):
client = MagicMock()
mock_put_file.side_effect = [
'test.noarch.rpm', 'test.tar.xz', 'test.py'
]

provider = IpaProvider(*args, **self.kwargs)
provider.inject = 'tests/data/injection/test_injection.yaml'

provider.process_injection_file(client)

mock_put_file.assert_has_calls([
call(client, '/home/user/test.noarch.rpm'),
call(client, '/home/user/test.tar.xz'),
call(client, '/home/user/test.py')
])

mock_install_package.assert_has_calls([
call(client, 'test.noarch.rpm'),
call(client, 'python3')
])

mock_extract_archive.assert_called_once_with(
client, 'test.tar.xz'
)

mock_execute_command.assert_called_once_with(
client, 'python test.py'
)

@patch.object(IpaProvider, '_set_instance_ip')
@patch.object(IpaProvider, '_set_image_id')
@patch.object(IpaProvider, '_start_instance_if_stopped')
Expand Down