Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Fix ssh config by letting fabric do it #148

Merged
merged 2 commits into from

2 participants

@michaelballantyne

Fix for issue #146.

Remove littlechef's credentials function, as fabric natively handles these functions with recent releases. Littlechef's attempts were conflicting with fabric's native functionality.

Tested with Fabric 1.4.2 (minimum version supported by littlechef) and 1.5.3 (most recent version).

Tested authentication scenarios include username, password and keypair provided in config.cfg, and Host, HostName, User, and IdentityFile provided in an ssh configuration specified by ssh-config.

@michaelballantyne michaelballantyne Remove use of credentials(). Fabric handles all those tasks
itself, and modifications made by credentials function interacted
negatively with fabric's functionality.
d17741f
@michaelballantyne michaelballantyne Username and keypair file should be valid credentials. 59302bd
@michaelballantyne

Second commit should probably be a second pull request but not sure how to make that happen. Previously either a password or ssh config was required. However, a username and keypair should be sufficient (assuming user can sudo without a password).

@tobami
Owner

This is actually awesome. There may be some regressions, but probably nothing that cannot be easily fixed.

In any case I can confirm that using user/password/ssh-config does work

@tobami tobami merged commit 67bb45e into from
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jan 29, 2013
  1. @michaelballantyne

    Remove use of credentials(). Fabric handles all those tasks

    michaelballantyne authored
    itself, and modifications made by credentials function interacted
    negatively with fabric's functionality.
  2. @michaelballantyne
This page is out of date. Refresh to see the latest.
View
22 littlechef/chef.py
@@ -78,22 +78,20 @@ def sync_node(node):
lib.print_header("Skipping dummy: {0}".format(env.host))
return False
current_node = lib.get_node(node['name'])
- with lib.credentials():
- # Always configure Chef Solo
- solo.configure(current_node)
- ipaddress = _get_ipaddress(node)
+ # Always configure Chef Solo
+ solo.configure(current_node)
+ ipaddress = _get_ipaddress(node)
# Everything was configured alright, so save the node configuration
# This is done without credentials, so that we keep the node name used
# by the user and not the hostname or IP translated by .ssh/config
filepath = save_config(node, ipaddress)
- with lib.credentials():
- try:
- # Synchronize the kitchen directory
- _synchronize_node(filepath, node)
- # Execute Chef Solo
- _configure_node()
- finally:
- _node_cleanup()
+ try:
+ # Synchronize the kitchen directory
+ _synchronize_node(filepath, node)
+ # Execute Chef Solo
+ _configure_node()
+ finally:
+ _node_cleanup()
return True
View
29 littlechef/lib.py
@@ -445,32 +445,3 @@ def get_margin(length):
margin_left = "\t\t\t\t"
chars = 4
return margin_left
-
-
-def credentials(*args, **kwargs):
- """Override default credentials with contents of .ssh/config,
-
- Only done if credentials are properly defined
- """
- if env.ssh_config:
- credentials = env.ssh_config.lookup(env.host)
- # translate from ssh params to fabric params
- if 'identityfile' in credentials:
- credentials['key_filename'] = credentials['identityfile']
- # SSH LogLevel != overall env loglevel, so don't override the env's
- # loglevel with SSH's
- if 'loglevel' in credentials:
- del credentials['loglevel']
- credentials.update(kwargs)
- else:
- credentials = kwargs
- # Expand the home directory of 'key_filename', as 'ssh' won't do it
- if credentials.get('key_filename'):
- credentials['key_filename'] = os.path.expanduser(
- credentials['key_filename'])
- # If ssh config defines a different Hostname string (be it domain or IP),
- # override 'host_string'
- if 'hostname' in credentials:
- credentials['host_string'] = credentials['hostname']
- credentials['user'] = env.user
- return settings(*args, **credentials)
View
10 littlechef/runner.py
@@ -226,11 +226,9 @@ def ssh(name):
# Execute remotely using either the sudo or the run fabric functions
with settings(hide("warnings"), warn_only=True):
if name.startswith("sudo "):
- with lib.credentials():
- sudo(name[5:])
+ sudo(name[5:])
else:
- with lib.credentials():
- run(name)
+ run(name)
def plugin(name):
@@ -415,8 +413,8 @@ def _readconfig():
except ConfigParser.NoOptionError:
pass
- if user_specified and not env.password and not env.ssh_config:
- abort('You need to define a password or a ssh-config file in config.cfg')
+ if user_specified and not env.password and not env.key_filename and not env.ssh_config:
+ abort('You need to define a password, keypair file, or ssh-config file in config.cfg')
# Node's Chef Solo working directory for storing cookbooks, roles, etc.
try:
View
129 littlechef/solo.py
@@ -22,7 +22,6 @@
from fabric.utils import abort
from littlechef import cookbook_paths
-from littlechef.lib import credentials
from littlechef import LOGFILE
@@ -32,76 +31,74 @@
def install(distro_type, distro, gems, version, stop_client):
"""Calls the appropriate installation function for the given distro"""
- with credentials():
- if distro_type == "debian":
- if gems == "yes":
- _gem_apt_install()
- else:
- _apt_install(distro, version, stop_client)
- elif distro_type == "rpm":
- if gems == "yes":
- _gem_rpm_install()
- else:
- _rpm_install()
- elif distro_type == "gentoo":
- _emerge_install()
- elif distro_type == "pacman":
- _gem_pacman_install()
+ if distro_type == "debian":
+ if gems == "yes":
+ _gem_apt_install()
else:
- abort('wrong distro type: {0}'.format(distro_type))
+ _apt_install(distro, version, stop_client)
+ elif distro_type == "rpm":
+ if gems == "yes":
+ _gem_rpm_install()
+ else:
+ _rpm_install()
+ elif distro_type == "gentoo":
+ _emerge_install()
+ elif distro_type == "pacman":
+ _gem_pacman_install()
+ else:
+ abort('wrong distro type: {0}'.format(distro_type))
def configure(current_node=None):
"""Deploy chef-solo specific files"""
current_node = current_node or {}
- with credentials():
- # Ensure that the /tmp/chef-solo/cache directory exist
- cache_dir = "{0}/cache".format(env.node_work_path)
- if not exists(cache_dir):
- with settings(hide('running', 'stdout'), warn_only=True):
- output = sudo('mkdir -p {0}'.format(cache_dir))
- if output.failed:
- error = "Could not create {0} dir. ".format(env.node_work_path)
- error += "Do you have sudo rights?"
- abort(error)
- # Change ownership of /tmp/chef-solo/ so that we can rsync
- with hide('running', 'stdout'):
- with settings(warn_only=True):
- output = sudo(
- 'chown -R {0} {1}'.format(env.user, env.node_work_path))
- if output.failed:
- error = "Could not modify {0} dir. ".format(env.node_work_path)
- error += "Do you have sudo rights?"
- abort(error)
- # Set up chef solo configuration
- logging_path = os.path.dirname(LOGFILE)
- if not exists(logging_path):
- sudo('mkdir -p {0}'.format(logging_path))
- if not exists('/etc/chef'):
- sudo('mkdir -p /etc/chef')
- # Set parameters and upload solo.rb template
- reversed_cookbook_paths = cookbook_paths[:]
- reversed_cookbook_paths.reverse()
- cookbook_paths_list = '[{0}]'.format(', '.join(
- ['"{0}/{1}"'.format(env.node_work_path, x) \
- for x in reversed_cookbook_paths]))
- data = {
- 'node_work_path': env.node_work_path,
- 'cookbook_paths_list': cookbook_paths_list,
- 'environment': current_node.get('chef_environment', '_default'),
- 'verbose': "true" if env.verbose else "false"
- }
- with settings(hide('everything')):
- try:
- upload_template(os.path.join(BASEDIR, 'solo.rb'), '/etc/chef/',
- context=data, use_sudo=True, backup=False, mode=0400)
- except SystemExit:
- error = ("Failed to upload '/etc/chef/solo.rb'\n"
- "This can happen when the deployment user does not have a "
- "home directory, which is needed as a temporary location")
- abort(error)
- with hide('stdout'):
- sudo('chown root:root {0}'.format('/etc/chef/solo.rb'))
+ # Ensure that the /tmp/chef-solo/cache directory exist
+ cache_dir = "{0}/cache".format(env.node_work_path)
+ if not exists(cache_dir):
+ with settings(hide('running', 'stdout'), warn_only=True):
+ output = sudo('mkdir -p {0}'.format(cache_dir))
+ if output.failed:
+ error = "Could not create {0} dir. ".format(env.node_work_path)
+ error += "Do you have sudo rights?"
+ abort(error)
+ # Change ownership of /tmp/chef-solo/ so that we can rsync
+ with hide('running', 'stdout'):
+ with settings(warn_only=True):
+ output = sudo(
+ 'chown -R {0} {1}'.format(env.user, env.node_work_path))
+ if output.failed:
+ error = "Could not modify {0} dir. ".format(env.node_work_path)
+ error += "Do you have sudo rights?"
+ abort(error)
+ # Set up chef solo configuration
+ logging_path = os.path.dirname(LOGFILE)
+ if not exists(logging_path):
+ sudo('mkdir -p {0}'.format(logging_path))
+ if not exists('/etc/chef'):
+ sudo('mkdir -p /etc/chef')
+ # Set parameters and upload solo.rb template
+ reversed_cookbook_paths = cookbook_paths[:]
+ reversed_cookbook_paths.reverse()
+ cookbook_paths_list = '[{0}]'.format(', '.join(
+ ['"{0}/{1}"'.format(env.node_work_path, x) \
+ for x in reversed_cookbook_paths]))
+ data = {
+ 'node_work_path': env.node_work_path,
+ 'cookbook_paths_list': cookbook_paths_list,
+ 'environment': current_node.get('chef_environment', '_default'),
+ 'verbose': "true" if env.verbose else "false"
+ }
+ with settings(hide('everything')):
+ try:
+ upload_template(os.path.join(BASEDIR, 'solo.rb'), '/etc/chef/',
+ context=data, use_sudo=True, backup=False, mode=0400)
+ except SystemExit:
+ error = ("Failed to upload '/etc/chef/solo.rb'\n"
+ "This can happen when the deployment user does not have a "
+ "home directory, which is needed as a temporary location")
+ abort(error)
+ with hide('stdout'):
+ sudo('chown root:root {0}'.format('/etc/chef/solo.rb'))
def check_distro():
@@ -110,7 +107,7 @@ def check_distro():
ubuntu_distros = ['natty', 'maverick', 'lucid', 'karmic']
rpm_distros = ['centos', 'rhel', 'sl']
- with credentials(
+ with settings(
hide('warnings', 'running', 'stdout', 'stderr'), warn_only=True):
output = sudo('cat /etc/issue')
if 'Debian GNU/Linux 5.0' in output:
View
33 tests/test_lib.py
@@ -514,38 +514,5 @@ def test_sync_node(self, mock_method1, mock_ipaddress, mock_method3,
self.assertTrue(chef.sync_node(test_node))
-class TestCredentials(unittest.TestCase):
- """Tests for the credentials function in lib"""
- def setUp(self):
- self.ssh_config = {
- 'identityfile': '/Users/myuser/.ssh/id_rsa',
- 'loglevel': 'ERROR',
- 'hostname': '1.1.1.1',
- 'passwordauthentication': 'no',
- 'userknownhostsfile': '/dev/null',
- 'user': 'myuser',
- 'stricthostkeychecking': 'no',
- 'port': '22'
- }
- runner.__testing__ = True
- runner.env.ssh_config = mock.MagicMock()
- runner.env.ssh_config.lookup.return_value = self.ssh_config
- runner.env.host = 'nodename'
-
- self.old_log_level = runner.env.loglevel
- runner.env.loglevel = 'original_loglevel'
-
- def tearDown(self):
- runner.env.ssh_config = None
- runner.env.host = None
- runner.env.loglevel = self.old_log_level
-
- def test_credentials_ignores_ssh_config_loglevel(self):
- """Ignores LogLevel in ssh config"""
- with lib.credentials():
- runner.env.ssh_config.lookup.assert_called_once_with('nodename')
- self.assertEqual(runner.env.loglevel, 'original_loglevel')
-
-
if __name__ == "__main__":
unittest.main()
Something went wrong with that request. Please try again.