Coder Social home page Coder Social logo

ssh_config's Introduction

SSH Config

PyPI version Build Status

SSH client config file manager

What is ssh_config?

https://linux.die.net/man/5/ssh_config

Why

I don't remember all the servers I am managing. Also all servers require all different configurations to connect to it. I know ~.ssh/config can handle this kind of issue. I want it to handle this file easier.

Yes, I am not sure this is easier way to handle it. but I am trying.

Requirements

After 0.0.15, Python27 is not supported.

Python 3.6 or higher

Installation

pip3 install ssh-config

Usage

Usage: ssh-config [OPTIONS] COMMAND [ARGS]...

Options:
  -f, --path TEXT       [default: /Users/jonghak.choi/.ssh/config]
  --debug / --no-debug
  --version             Show the version and exit.
  --help                Show this message and exit.

Commands:
  add         Add SSH Config into config file
  attributes  Print possible attributes for Host
  gen         Generate the ssh config
  get         Get ssh config with name
  ls          Enumerate the configs
  remove
  rename
  ssh         Interative shell for Host
  update      Update the ssh Host config Attribute key=value format

Use-cases

List hosts

$ ssh-config ls
server1
server_cmd_1
server_cmd_2
server_cmd_3

$ ssh-config ls -l
server1			10.0.2.10
server_cmd_1	10.0.1.11
server_cmd_2	10.0.1.12
server_cmd_3	10.0.1.13
Add host
$ ssh-config add "server_cmd_4" HostName=203.0.113.77 IdentityFile="~/.ssh/cmd_id_rsa"
Update host
$ ssh-config update "server_cmd_3" IdentityFile="~/.ssh/cmd_id_rsa"
Remove host
$ ssh-config remove "server_3"

Using pattern to get list or update exist hosts

add ssh key to multiple servers

ssh-config ls | xargs -I{} ssh-copy-id -i ~/.ssh/id_rsa {}

Export ssh-config to ansible inventory ini format.

https://docs.ansible.com/ansible/latest/dev_guide/developing_inventory.html?extIdCarryOver=true&sc_cid=701f2000001OH7EAAW#inventory-script-conventions

ssh-config inventory --list|--host <hostname>

ssh_config's People

Contributors

citystar avatar dependabot[bot] avatar haginara avatar kiarn avatar petru-ghita avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

ssh_config's Issues

Fix "KeyError: 'No'" for "No" values

It is better to change the line at

return convert[value]

to the following. Otherwise, "No" values would run into KeyError: 'No' errors.

convert[value.lower()]

I suggest the code to look like

def yes_or_no(value: str) -> bool:
    """Convert 'yes' or 'no' to True or False
    Args:
        value (str): The string containing 'yes' or 'no'
    Returns:
        bool: True if value is 'yes', False if value is 'no'
    """
    if value is None:
        return
    if value.lower() not in ('yes', 'no', 'true', 'false'):
        raise TypeError(f"Yes or No is required: {value}")
    convert = {
        "yes": True,
        "no": False,
        "true": True,
        "false": False,
        True: "yes",
        False: "no",
    }
    return convert[value.lower()]

Otherwise, I would run into errors when reading back the updated config file.

Allow non-interactive ssh-add

I want to put this as bash aliases, but I don't see any option to omit interactive question.

$ ssh-config add "cvps" HostName=192.168.140.1 Port=22 User=chris IdentityFile=""
Host cvps
    HostName 192.168.140.1
    User chris
    Port 22

Information is correct ? [y/N]: y
Added!
$

You should add --yes so one don't have to manually press y. Thanks ! Great program overall

Keys should be case-insensitive

If I parse a file like:

Host myhost
    hostname myhost.mydomain.com

The parsed hosts gets the attribute HostName = None. However SSH_CONFIG(5) indicates that keywords are case insensitive.

Does not follow Include keyword

It would be nice if this could recursively include files listed in the config file

From 7.3p1 and up, there is the Include keyword

     Include
             Include the specified configuration file(s).  Multiple
             pathnames may be specified and each pathname may contain
             glob(7) wildcards and, for user configurations, shell-like
             ‘~’ references to user home directories.  Wildcards will be
             expanded and processed in lexical order.  Files without
             absolute paths are assumed to be in ~/.ssh if included in a
             user configuration file or /etc/ssh if included from the
             system configuration file.  Include directive may appear
             inside a Match or Host block to perform conditional
             inclusion.

Source: ssh_config(5).

Unindented block and global options

Hello @haginara

Thanks for this useful lib.
I just found out that ssh_config does not support global options at the beginning of the file and unindented block ( indenting a block is always a good practice, but it's not required in the ssh config file ).

Here a dummy example of config file which leads to a WrongSSHConfig :

CanonicalizeHostname no
CanonicalDomains no

Host github.com
    User git
    IdentityFile ~/.ssh/id_github

or simply

Host github.com
User git
IdentityFile ~/.ssh/id_github

But both files have a "good" syntax.

I tried to modify the pattern defined with pyparsing in order to parse the unindented global options, but it only works partially :

    def parse(self, data=""):
        """Parse ssh-config data

        args:
            data (str)

        returns:
            Parsed config or None (dict)
        """

        if data:
            self.raw = data

        SPACE = White().suppress()
        SEP = Suppress(SPACE) | Suppress("=")
        HOST = CaselessLiteral("Host").suppress()
        MATCH = CaselessLiteral("Match").suppress()
        KEY = Word(alphanums)
        VALUE = Word(alphanums + ' ~%*?!._-+/,"')
        paramValueDef = SkipTo("#" | lineEnd)
        indentStack = [1]

        HostDecl = (HOST | MATCH) + SEP + VALUE
        paramDef = Dict(Group(~HOST + KEY + SEP + paramValueDef))
        block = indentedBlock(paramDef, indentStack)
        HostBlock = Dict(Group(HostDecl + block))
        Begin = Empty().setParseAction(replaceWith("GLOBAL_OPTIONS"))
        GlobalOptions = Group(ZeroOrMore(Dict(Group(paramDef))))
        try:
            return (Begin + GlobalOptions + OneOrMore(HostBlock)).ignore(pythonStyleComment).parseString(self.raw)
        except ParseException as e:
            print(e)
        return None

The idea is to parse an eventual first unindented block without host definition, and add the keyword "GLOBAL_OPTIONS" to this block in order to have a proper dict.

It seems to work with the parsed object, but not for the conversion .asDict() :

# parsed :
['GLOBAL_OPTIONS', [[['CanonicalizeHostname', 'no']], [['CanonialDomains', 'no']]], ['github.com', [[['User', 'git']], [['IdentityFile', '~/.ssh/id_github']]]]]

# parsed.asDict() : 
{'github.com': [{'User': 'git'}, {'IdentityFile': '~/.ssh/id_github'}]}

The block "GLOBAL_OPTIONS" appears correctly in the object, but is not converted in the resulted dict.
Since I don't know the lib pyparsing very well, there's maybe an easier way to achieve this, and maybe you have a better idea for this, it would be great.

Thanks

Arnaud

How does `ssh-config update` work?

I tried reading through the source, but it is somewhat confusing.

On running:

ssh-config update
Traceback (most recent call last):
  File "/miniconda3/envs/b37/bin/ssh-config", line 10, in <module>
    sys.exit(main())
  File "/miniconda3/envs/b37/lib/python3.7/site-packages/ssh_config/cli.py", line 98, in main
    argv[1:], options_first=True, version="ssh_config %s" % __version__
  File "/miniconda3/envs/b37/lib/python3.7/site-packages/ssh_config/cli.py", line 72, in __init__
    command_cls = getattr(commands, command_name)
AttributeError: module 'ssh_config.commands' has no attribute 'Update'

There seems to also be no docs and no -h command for subcommands.

pip install fails on 0.0.12

Versions:
python: 2.7.16
pip: 19.1.1

pip install ssh-config
errror:

 Using cached https://files.pythonhosted.org/packages/b3/a2/72ca9d7c0b181b58d462647421ba1531ce3a62ca9b1c8b65c29c3a0349b9/ssh_config-0.0.12.tar.gz
    ERROR: Complete output from command python setup.py egg_info:
    ERROR: Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/private/var/folders/2z/k2bsyg654t3bky0c96fntfj80000gn/T/pip-install-_NfBMw/ssh-config/setup.py", line 7, in <module>
        from ssh_config import __version__
      File "ssh_config/__init__.py", line 1, in <module>
        from .client import SSHConfig, Host, EmptySSHConfig
      File "ssh_config/client.py", line 5, in <module>
        from pyparsing import (
    ImportError: No module named pyparsing
    ----------------------------------------
ERROR: Command "python setup.py egg_info" failed with error code 1 in /private/var/folders/2z/k2bsyg654t3bky0c96fntfj80000gn/T/pip-install-_NfBMw/ssh-config/

It appears that this import: https://github.com/haginara/ssh_config/blob/develop/setup.py#L7
is causing the import of client.py which requires pyparsing which is not yet installed in a new environment.

Support multiple host patterns

SSH_CONFIG supports defining multiple host patterns:

Host  pattern1 pattern2
    IdentityFile file

But parsing this at the moment fails with an issue in pyparsing.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.