Skip to content

Commit

Permalink
use the current interpreter's pip or easy_install to install python p…
Browse files Browse the repository at this point in the history
…ackages

fixes awslabs#2
  • Loading branch information
Jonathan Stewmon committed Oct 6, 2016
1 parent 3b43117 commit 5a52ade
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 22 deletions.
33 changes: 18 additions & 15 deletions src/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@
3. any other version of collectd is not supported.
"""

import errno
import os
import platform
import re
import shlex
import shutil
import sys
import time
import errno
from collections import namedtuple
from distutils.version import LooseVersion
from glob import glob
Expand All @@ -39,10 +40,10 @@
PLUGIN_CONFIGURATION_INCLUDE_LINE = 'Include "/etc/collectd-cloudwatch.conf"\r\n'
APT_INSTALL_COMMAND = "apt-get install -y "
YUM_INSTALL_COMMAND = "yum install -y "
SYSTEM_DEPENDENCIES = ["python-pip", "python-setuptools"]
PIP_INSTALLATION_FLAGS = " install --quiet --upgrade --force-reinstall "
EASY_INSTALL_COMMAND = "easy_install -U --quiet "
PYTHON_DEPENDENCIES = ["requests"]
SYSTEM_DEPENDENCIES = []
PIP_INSTALL_COMMAND = sys.executable + " -m pip install --quiet --upgrade --force-reinstall "
EASY_INSTALL_COMMAND = sys.executable + " -m easy_install -U --quiet "
PYTHON_DEPENDENCIES = ["requests>=2.4.0"]
FIND_COMMAND = "which {} 2> /dev/null"
COLLECTD_HELP_ARGS = "-help"
CONFIG_FILE_REGEX = re.compile("\sConfig file\s*(.*)\s")
Expand Down Expand Up @@ -236,22 +237,24 @@ class MetadataRequestException(Exception):


def install_python_packages(packages):
try:
Command(detect_pip() + PIP_INSTALLATION_FLAGS + " ".join(packages), "Installing python dependencies", exit_on_failure=True).run()
except CalledProcessError:
Command(EASY_INSTALL_COMMAND + " ".join(packages), "Installing python dependencies", exit_on_failure=True).run()
if packages:
try:
detect_pip()
except CalledProcessError:
command = Command(EASY_INSTALL_COMMAND + " ".join(packages), "Installing python dependencies", exit_on_failure=True)
else:
command = Command(PIP_INSTALL_COMMAND + " ".join(packages), "Installing python dependencies", exit_on_failure=True)
command.run()


def detect_pip():
try:
return get_path_to_executable("pip")
except CalledProcessError:
return get_path_to_executable("python-pip")
Command("{} -m pip".format(sys.executable), "Checking if pip is installed").run()


def install_packages(packages):
command = DISTRIBUTION_TO_INSTALLER[detect_linux_distribution()] + " ".join(packages)
Command(command, "Installing dependencies").run()
if packages:
command = DISTRIBUTION_TO_INSTALLER[detect_linux_distribution()] + " ".join(packages)
Command(command, "Installing dependencies").run()


def detect_linux_distribution():
Expand Down
16 changes: 9 additions & 7 deletions test/test_setup.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import sys
import unittest
from subprocess import CalledProcessError

Expand Down Expand Up @@ -98,21 +99,22 @@ def test_required_command_exits_on_failure(self):
class InstallationTest(unittest.TestCase):
PYTHON_MODULES = ["invalid_module1", "invalid_module2"]

@patch("src.setup.detect_pip")
@patch("src.setup.Command")
def test_install_python_packages_uses_pip_first(self, command_mock):
def test_install_python_packages_uses_pip_first(self, command_mock, detect_pip_mock):
installer.detect_pip = Mock()
installer.detect_pip.return_value = "pip"
installer.detect_pip.return_value = None
command_mock.return_value = Mock()
installer.install_python_packages(self.PYTHON_MODULES)
command_mock.assert_called_with("pip install --quiet --upgrade --force-reinstall " + " ".join(self.PYTHON_MODULES), 'Installing python dependencies', exit_on_failure=True)
command_mock.assert_called_with(sys.executable + " -m pip install --quiet --upgrade --force-reinstall " + " ".join(self.PYTHON_MODULES), 'Installing python dependencies', exit_on_failure=True)

@patch("src.setup.detect_pip")
@patch("src.setup.Command")
def test_install_python_packages_uses_easy_install_when_pip_is_not_available(self, command_mock):
installer.detect_pip = Mock()
installer.detect_pip.side_effect = CalledProcessError(cmd="which python-pip", returncode=1)
def test_install_python_packages_uses_easy_install_when_pip_is_not_available(self, command_mock, detect_pip_mock):
detect_pip_mock.side_effect = CalledProcessError(cmd="{} -m pip".format(sys.executable), returncode=1)
command_mock.return_value = Mock()
installer.install_python_packages(self.PYTHON_MODULES)
command_mock.assert_called_with("easy_install -U --quiet " + " ".join(self.PYTHON_MODULES), "Installing python dependencies", exit_on_failure=True)
command_mock.assert_called_with(sys.executable + " -m easy_install -U --quiet " + " ".join(self.PYTHON_MODULES), "Installing python dependencies", exit_on_failure=True)


class ColorTest(unittest.TestCase):
Expand Down

1 comment on commit 5a52ade

@unixengineer
Copy link

Choose a reason for hiding this comment

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

Installing python27-pip package fixes the issue

Issue:

# python ./setup.py
Installing dependencies ... OK
Installing python dependencies ... OK
Downloading plugin ... OK
Extracting plugin ... OK
Moving to collectd plugins directory ... OK
Copying CloudWatch plugin include file ... OK
INFO:urllib3.connectionpool:Starting new HTTP connection (1): 169.254.169.254

AWS region could not be automatically detected. Cause:Cannot access metadata service. Cause: Timeout value connect was (0.3, 0.5), but it must be an int or float.
Enter one of the available regions from: http://docs.aws.amazon.com/general/latest/gr/rande.html#cw_region
Enter region: ^CTraceback (most recent call last):
  File "./setup.py", line 964, in <module>
    main()
  File "./setup.py", line 957, in main
    install_plugin()
  File "./setup.py", line 876, in install_plugin
    supply_config()
  File "./setup.py", line 892, in supply_config
    _prepare_plugin_config(config)
  File "./setup.py", line 912, in _prepare_plugin_config
    debug).run()
  File "./setup.py", line 362, in run
    self._configure_region()
  File "./setup.py", line 422, in _configure_region
    self.config.region = self._get_region()
  File "./setup.py", line 427, in _get_region
    message="Enter region: ").run()
  File "./setup.py", line 631, in run
    return self._get_answer()
  File "./setup.py", line 634, in _get_answer
    value = raw_input(self.message).strip()
KeyboardInterrupt

Resolution:

# yum install python27-pip
# python ./setup.py
Installing dependencies ... OK
Installing python dependencies ... OK
Downloading plugin ... OK
Extracting plugin ... OK
Moving to collectd plugins directory ... OK
Copying CloudWatch plugin include file ... OK
DEBUG:urllib3.util.retry:Converted retries value: 1 -> Retry(total=1, connect=None, read=None, redirect=None, status=None)
DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): 169.254.169.254
DEBUG:urllib3.connectionpool:http://169.254.169.254:80 "GET /latest/meta-data/placement/availability-zone/ HTTP/1.1" 200 10

Choose AWS region for published metrics:
  1. Automatic [us-west-2]
  2. Custom
Enter choice [1]

Please sign in to comment.