Skip to content

Commit

Permalink
Add RHEL7 support for codedeploy
Browse files Browse the repository at this point in the history
  • Loading branch information
feverLu authored and jamesls committed Jun 24, 2015
1 parent 396a5cc commit 44c7cc1
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 42 deletions.
57 changes: 35 additions & 22 deletions awscli/customizations/codedeploy/systems.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@


class System:
UNSUPPORTED_SYSTEM_MSG = (
'Only Ubuntu Server, Red Hat Enterprise Linux Server and '
'Windows Server operating systems are supported.'
)

def __init__(self, params):
self.session = params.session
self.s3 = self.session.create_client(
Expand Down Expand Up @@ -158,18 +163,7 @@ def install(self, params):
self.INSTALLER = params.installer

self._update_system(params)

process = subprocess.Popen(
['service', 'codedeploy-agent', 'stop'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
(output, error) = process.communicate()
not_found = 'codedeploy-agent: unrecognized service'
if process.returncode != 0 and not_found not in error:
raise RuntimeError(
'Failed to stop the AWS CodeDeploy Agent:\n{0}'.format(error)
)
self._stop_agent(params)

response = self.s3.get_object(Bucket=params.bucket, Key=params.key)
with open(self.INSTALLER, 'wb') as f:
Expand All @@ -192,25 +186,28 @@ def install(self, params):
)

def uninstall(self, params):
process = self._stop_agent(params)
if process.returncode == 0:
self._remove_agent(params)

def _update_system(self, params):
raise NotImplementedError('preinstall')

def _remove_agent(self, params):
raise NotImplementedError('remove_agent')

def _stop_agent(self, params):
process = subprocess.Popen(
['service', 'codedeploy-agent', 'stop'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
(output, error) = process.communicate()
not_found = 'codedeploy-agent: unrecognized service'
if process.returncode == 0:
self._remove_agent(params)
elif not_found not in error:
if process.returncode != 0 and params.not_found_msg not in error:
raise RuntimeError(
'Failed to stop the AWS CodeDeploy Agent:\n{0}'.format(error)
)

def _update_system(self, params):
raise NotImplementedError('preinstall')

def _remove_agent(self, params):
raise NotImplementedError('remove_agent')
return process


class Ubuntu(Linux):
Expand All @@ -220,3 +217,19 @@ def _update_system(self, params):

def _remove_agent(self, params):
subprocess.check_call(['dpkg', '-r', 'codedeploy-agent'])

def _stop_agent(self, params):
params.not_found_msg = 'codedeploy-agent: unrecognized service'
return Linux._stop_agent(self, params)


class RHEL(Linux):
def _update_system(self, params):
subprocess.check_call(['yum', '-y', 'install', 'ruby'])

def _remove_agent(self, params):
subprocess.check_call(['yum', '-y', 'erase', 'codedeploy-agent'])

def _stop_agent(self, params):
params.not_found_msg = 'Redirecting to /bin/systemctl stop codedeploy-agent.service'
return Linux._stop_agent(self, params)
7 changes: 4 additions & 3 deletions awscli/customizations/codedeploy/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import re

from awscli.compat import urlopen, URLError
from awscli.customizations.codedeploy.systems import Ubuntu, Windows
from awscli.customizations.codedeploy.systems import System, Ubuntu, Windows, RHEL
from socket import timeout

MAX_INSTANCE_NAME_LENGTH = 100
Expand Down Expand Up @@ -101,12 +101,13 @@ def validate_instance(params):
if platform.system() == 'Linux':
if 'Ubuntu' in platform.linux_distribution()[0]:
params.system = Ubuntu(params)
if 'Red Hat Enterprise Linux Server' in platform.linux_distribution()[0]:
params.system = RHEL(params)
elif platform.system() == 'Windows':
params.system = Windows(params)
if 'system' not in params:
raise RuntimeError(
'Only Ubuntu Server and Windows Server operating systems are '
'supported.'
System.UNSUPPORTED_SYSTEM_MSG
)
try:
urlopen('http://169.254.169.254/latest/meta-data/', timeout=1)
Expand Down
6 changes: 2 additions & 4 deletions tests/unit/customizations/codedeploy/test_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

from argparse import Namespace
from awscli.customizations.codedeploy.install import Install
from awscli.customizations.codedeploy.systems import Ubuntu, Windows
from awscli.customizations.codedeploy.systems import Ubuntu, Windows, RHEL, System
from awscli.testutils import unittest
from mock import MagicMock, patch, mock_open
from socket import timeout
Expand Down Expand Up @@ -101,9 +101,7 @@ def test_install_throws_on_invalid_region(self):
def test_install_throws_on_unsupported_system(self):
self.system.return_value = 'Unsupported'
with self.assertRaisesRegexp(
RuntimeError,
'Only Ubuntu Server and Windows Server operating systems are '
'supported.'):
RuntimeError, System.UNSUPPORTED_SYSTEM_MSG):
self.install._run_main(self.args, self.globals)

def test_install_throws_on_ec2_instance(self):
Expand Down
79 changes: 74 additions & 5 deletions tests/unit/customizations/codedeploy/test_systems.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

from argparse import Namespace
from mock import MagicMock, patch, call, mock_open
from awscli.customizations.codedeploy.systems import Windows, Ubuntu
from awscli.customizations.codedeploy.systems import Windows, Ubuntu, RHEL
from awscli.testutils import unittest


Expand Down Expand Up @@ -150,8 +150,7 @@ def test_uninstall(self):
call().communicate()
])


class TestUbuntu(unittest.TestCase):
class TestLinux(unittest.TestCase):
def setUp(self):
self.popen_patcher = patch('subprocess.Popen')
self.popen = self.popen_patcher.start()
Expand Down Expand Up @@ -208,13 +207,17 @@ def setUp(self):
self.params.bucket = self.bucket
self.params.key = self.key

self.ubuntu = Ubuntu(self.params)

def tearDown(self):
self.popen_patcher.stop()
self.check_call_patcher.stop()
self.open_patcher.stop()
self.environ_patcher.stop()


class TestUbuntu(TestLinux):
def setUp(self):
super(self.__class__, self).setUp()
self.ubuntu = Ubuntu(self.params)

def test_config_dir(self):
self.assertEquals(self.config_dir, self.ubuntu.CONFIG_DIR)
Expand Down Expand Up @@ -279,6 +282,72 @@ def test_uninstall(self):
call(['dpkg', '-r', 'codedeploy-agent'])
])

class TestRHEL(TestLinux):
def setUp(self):
super(self.__class__, self).setUp()
self.rhel = RHEL(self.params)

def test_config_dir(self):
self.assertEquals(self.config_dir, self.rhel.CONFIG_DIR)

def test_config_file(self):
self.assertEquals(self.config_file, self.rhel.CONFIG_FILE)

def test_config_path(self):
self.assertEquals(self.config_path, self.rhel.CONFIG_PATH)

def test_installer(self):
self.assertEquals(self.installer, self.rhel.INSTALLER)

@patch('os.geteuid')
def test_validate_administrator_throws(self, geteuid):
geteuid.return_value = 1
with self.assertRaisesRegexp(
RuntimeError, 'You must run this command as sudo.'):
self.rhel.validate_administrator()

def test_install(self):
process = MagicMock()
process.communicate.return_value = ('', '')
process.returncode = 0
self.popen.return_value = process
self.rhel.install(self.params)
self.popen.assert_has_calls([
call(
['service', 'codedeploy-agent', 'stop'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
),
call().communicate()
])
self.check_call.assert_has_calls([
call(['yum', '-y', 'install', 'ruby']),
call(['chmod', '+x', './{0}'.format(self.installer)]),
call(
['./{0}'.format(self.installer), 'auto'],
env=self.environment
)
])
self.open.assert_called_with(self.installer, 'wb')
self.open().write.assert_called_with(self.body)

def test_uninstall(self):
process = MagicMock()
process.communicate.return_value = ('', '')
process.returncode = 0
self.popen.return_value = process
self.rhel.uninstall(self.params)
self.popen.assert_has_calls([
call(
['service', 'codedeploy-agent', 'stop'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
),
call().communicate()
])
self.check_call.assert_has_calls([
call(['yum', '-y', 'erase', 'codedeploy-agent'])
])

if __name__ == "__main__":
unittest.main()
16 changes: 12 additions & 4 deletions tests/unit/customizations/codedeploy/test_uninstall.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import sys

from argparse import Namespace
from awscli.customizations.codedeploy.systems import Ubuntu, Windows
from awscli.customizations.codedeploy.systems import Ubuntu, Windows, RHEL, System
from awscli.customizations.codedeploy.uninstall import Uninstall
from awscli.testutils import unittest
from mock import MagicMock, patch
Expand Down Expand Up @@ -68,9 +68,7 @@ def test_uninstall_throws_on_invalid_region(self):
def test_uninstall_throws_on_unsupported_system(self):
self.system.return_value = 'Unsupported'
with self.assertRaisesRegexp(
RuntimeError,
'Only Ubuntu Server and Windows Server operating systems are '
'supported.'):
RuntimeError, System.UNSUPPORTED_SYSTEM_MSG):
self.uninstall._run_main(self.args, self.globals)

def test_uninstall_throws_on_ec2_instance(self):
Expand All @@ -97,6 +95,16 @@ def test_uninstall_for_ubuntu(self, uninstall):
'/etc/codedeploy-agent/conf/codedeploy.onpremises.yml'
)

@patch.object(RHEL, 'uninstall')
def test_uninstall_for_RHEL(self, uninstall):
self.system.return_value = 'Linux'
self.linux_distribution.return_value = ('Red Hat Enterprise Linux Server', '', '')
self.uninstall._run_main(self.args, self.globals)
uninstall.assert_called_with(self.args)
self.remove.assert_called_with(
'/etc/codedeploy-agent/conf/codedeploy.onpremises.yml'
)

@patch.object(Windows, 'uninstall')
@patch.object(Windows, 'validate_administrator')
def test_uninstall_for_windows(self, validate_administrator, uninstall):
Expand Down
16 changes: 12 additions & 4 deletions tests/unit/customizations/codedeploy/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from socket import timeout
from argparse import Namespace
from mock import MagicMock, patch
from awscli.customizations.codedeploy.systems import Ubuntu, Windows
from awscli.customizations.codedeploy.systems import Ubuntu, Windows, RHEL, System
from awscli.customizations.codedeploy.utils import \
validate_region, validate_instance_name, validate_tags, \
validate_iam_user_arn, validate_instance, validate_s3_location, \
Expand Down Expand Up @@ -152,6 +152,16 @@ def test_validate_instance_ubuntu(self):
self.assertIn('system', self.params)
self.assertTrue(isinstance(self.params.system, Ubuntu))

def test_validate_instance_rhel(self):
self.urlopen.side_effect = timeout('Not EC2 instance')
self.system.return_value = 'Linux'
self.linux_distribution.return_value = ('Red Hat Enterprise Linux Server', None, None)
self.params.session = self.session
self.params.region = self.region
validate_instance(self.params)
self.assertIn('system', self.params)
self.assertTrue(isinstance(self.params.system, RHEL))

def test_validate_instance_windows(self):
self.urlopen.side_effect = timeout('Not EC2 instance')
self.system.return_value = 'Windows'
Expand All @@ -164,9 +174,7 @@ def test_validate_instance_windows(self):
def test_validate_instance_throws_on_unsupported_system(self):
self.system.return_value = 'Unsupported'
with self.assertRaisesRegexp(
RuntimeError,
'Only Ubuntu Server and Windows Server operating systems are '
'supported.'):
RuntimeError, System.UNSUPPORTED_SYSTEM_MSG):
validate_instance(self.params)

def test_validate_instance_throws_on_ec2_instance(self):
Expand Down

0 comments on commit 44c7cc1

Please sign in to comment.