def update_ssh_config(config_path, instances, pem_dir_path, new_config_path=None): """ Update SSH config file to include the given AWS EC2 instances. Entries will be added (updated) in the SSH config file. Example: Host host_alias HostName my_aws_host.compute.amazonaws.com User ec2-user IdentityFile /Users/paul/.ssh/amazon_aws/plisdku-admin-aws-key-pair-us-west-1.pem Args: config_path (str): path to SSH config file, e.g. ~/.ssh/config instances (list): list of boto3.resources.factory.ec2.Instance references new_config_path (str, optional): path for writing config file """ config_path = os.path.expanduser(config_path) if new_config_path is None: new_config_path = config_path else: new_config_path = os.path.expanduser(config_path) try: c = sshconf.read_ssh_config(config_path) except FileNotFoundError: raise for instance in instances: items = get_instance_ssh_config_items(instance, pem_dir_path) if items["Host"] in c.hosts(): c.remove(items["Host"]) c.add(items["Host"], Hostname=items["Hostname"], User=items["User"], IdentityFile=items["IdentityFile"]) c.write(new_config_path)
def __init__(self, host): try: # Read the local ssh config configs = read_ssh_config(join(expanduser('~'), '.ssh', 'config')) if host not in configs.hosts(): raise ValueError( "{} not configured in ~/.ssh/config".format(host)) config = configs.host(host) # initialize fields on the object with entries in the ssh config self.__dict__.update(config) # also find the local port which is forwarded to the remote mysql daemon self.mysql_port = SshConfig.mysql_port(config) # and include the config section name self.ssh_host = host except Exception as ex: print( ex, "Do you have your ~/.ssh/config set up to forward a local port to 3306 on {}? " .format(host) + "If not, see https://confluence.dev.clover.com/pages/viewpage.action?pageId=20711161", file=sys.stderr) raise ex
def validate(self): if self.edtConnectionName.text() == "": self.showMsg("Please enter the connection name", "err") return False elif self.edtSingularityFolder.text() == "": self.showMsg("Please enter the remote singularity folder name", "err") return False elif self.edtProjectRootFolder.text() == "": self.showMsg("Please enter the remote project root folder name", "err") return False config = read_ssh_config(os.path.expanduser("~/.ssh/config")) settings = config.host(self.cmbHost.currentText()) keys = {k.lower(): v for k, v in settings.items()} if "user" not in keys: self.showMsg( "SSH config file does not provide user for host %s" % self.cmbHost.currentText(), "err") return False if "proxycommand" not in keys: self.showMsg( "SSH config file does not provide ProxyCommand for host %s" % self.cmbHost.currentText(), "err") return False self.accept() return True
def __init__(self, config: LocalConfig): self.config: LocalConfig = config # TODO: Handle missing config/not configured. ssh_config = read_ssh_config(SSH_CONFIG_PATH) self.bind_hostname = ssh_config.host(BIND_HOST)["hostname"] self.bind_port = ssh_config.host(BIND_HOST)["port"]
def __init__(self, host, printer=StatusPrinter): try: # Read the local ssh config configs = read_ssh_config(join(expanduser('~'), '.ssh', 'config')) if host not in configs.hosts(): raise ValueError( "{} not configured in ~/.ssh/config".format(host)) config = configs.host(host) # initialize fields on the object with entries in the ssh config config['hostname'] # throw if not set self.__dict__.update(config) # also find the local ports which are is forwarded to the remote mysql daemon and the admin interface (http) ports = SshConfig._get_ports(config, printer) self._mysql_port = ports.mysql self._admin_http_port = ports.admin # ssh tunnel not used for external-facing access, assume port 80 self._http_port = 80 # and include the config section name self._ssh_host = host except Exception as ex: printer(ex) printer( "Do you have your ~/.ssh/config set up to forward a local port to 3306 on {}? " .format(host) + "If not, see https://confluence.dev.clover.com/pages/viewpage.action?pageId=20711161" ) raise ex
def teardown(): """Deletes project lassh configuration and removes associated nicknames from the global namespace""" checkFiles() success = deleteInclude() if success: puts(colored.green('Deleted include from global ssh_config')) else: puts(colored.yellow('Include not found in global ssh_config')) # Remove nicknames associated with this lassh config. config = read_ssh_config(LASSH_CONFIG_PATH.resolve()) hostnames = set(config.hosts()) with open(HOME_LASSH_NAMESPACE_PATH, 'r+') as namespace_file: names = namespace_file.readlines() namespace_file.seek(0) for name in names: if name.rstrip() not in hostnames: namespace_file.write(name) namespace_file.truncate() # Delete lassh.config file LASSH_CONFIG_PATH.unlink()
def test_read_included_glob(tmpdir): conf = tmpdir.join("config") incl = tmpdir.mkdir("conf.d").join("included_host") conf.write(""" Host svu.local Hostname ssh.svu.local User something Include conf.d/* """) incl.write(""" Host svu.included Hostname ssh.svu.included User whatever """) c = sshconf.read_ssh_config(conf) hosts = c.hosts() print("hosts", hosts) assert 'svu.local' in hosts assert 'svu.included' in hosts
def test_read_duplicate_keys(): c = sshconf.read_ssh_config(test_config2) host = c.host('foo') assert 5 == len(host.keys()) assert "localforward" in host assert 2 == len(host["localforward"])
def test_save(): import tempfile tc = os.path.join(tempfile.gettempdir(), "temp_ssh_config-4123") try: c = sshconf.read_ssh_config(test_config) c.set("svu", Hostname="ssh.svuniversity.ac.in", User="******") c.write(tc) c2 = sshconf.read_ssh_config(tc) assert c2.host("svu")["hostname"] == "ssh.svuniversity.ac.in" assert c2.host("svu")["user"] == "mca" assert c.config() == c2.config() finally: os.remove(tc)
def test_parsing(): c = sshconf.read_ssh_config(test_config) assert len(c.hosts()) == 2 assert c.host("*")["user"] == "something" assert c.host("svu")["proxycommand"] == "nc -w 300 -x localhost:9050 %h %p" s1 = c.config().splitlines() s2 = open(test_config).readlines() assert len(s1) == len(s2)
def _configure_openssh(): header("GProxy OpenSSH config") if os.path.exists(SSH_CONFIG_PATH): ssh_config = read_ssh_config(SSH_CONFIG_PATH) # Check and create a compliant config: changed = False host_config = ssh_config.host(HOST) if len(host_config) == 0: changed = True ssh_config.add(HOST, **ENTRY_DEFAULT) else: for key, default in ENTRY_REQUIRED.items(): if key.lower() not in host_config: changed = True ssh_config.set(HOST, **{key: default}) # Old config: if changed: new_config_str = ssh_config.config() old_config_str = read_ssh_config(SSH_CONFIG_PATH).config() print( f"Some changes are needed for your ssh config file ({SSH_CONFIG_PATH}):" ) show_line_diff(old=old_config_str.split("\n"), new=new_config_str.split("\n")) if yes_no("Do you want us to make these changes?", default=True): ssh_config.save() else: print( "Your SSH config file is already configured correctly. No changes needed." ) else: ssh_config = empty_ssh_config_file() ssh_config.add(HOST, **ENTRY_DEFAULT) print( f"No ssh config found at {SSH_CONFIG_PATH}. We need to create this file:" ) show_file(ssh_config.config().split("\n")) if yes_no("Do you want us to create the file?", default=True): _create_dir(SSH_CONFIG_PATH) ssh_config.write(SSH_CONFIG_PATH)
def test_set(): c = sshconf.read_ssh_config(test_config) c.set("svu", Compression="no", Port=2222) print(c.config()) print("svu", c.host('svu')) assert " Compression no" in c.config() assert " Port 2222" in c.config()
def test_mapping_set_new_key(): c = sshconf.read_ssh_config(test_config) c.set("svu", forwardAgent='yes', unknownpropertylikethis='noway') assert "Hostname www.svuniversity.ac.in" in c.config() # old parameters assert "Port 22" in c.config() assert "ForwardAgent yes" in c.config( ) # new parameter has been properly cased assert "unknownpropertylikethis noway" in c.config()
class SuperSSH(object): ssh_hosts = filter(lambda x: '*' not in x, read_ssh_config(expanduser("~/.ssh/config")).hosts()) def __init__(self, layout='main-horizontal'): self.layout = layout @staticmethod def ssh_host_filter(pattern): return fnmatch.filter(SuperSSH.ssh_hosts, pattern) def _init_tmux(self): server = libtmux.Server() session = server.new_session('test5', window_command='pwd', window_name='asdf') window = session.new_window(attach=False, window_name="ha in the bg") # window.select_window()\ session.attach_session() def multi(self, pattern): if '*' not in pattern: pattern += '*' hosts = SuperSSH.ssh_host_filter(pattern) if not hosts: print("Not match any hosts") exit() server = libtmux.Server() session = server.new_session( session_name='ssh-%s-%d' % (pattern.replace("*", ""), random.randint(1000, 9999)), ) w1 = session.attached_window w1.move_window(99) w = session.new_window(attach=True, ) for i, host in enumerate(hosts, start=1): if i == 1: p = w.attached_pane else: p = w.split_window( attach=False, target=p.id, ) p.send_keys("printf '\\033]2;%s\\033\\\\'" % host) p.cmd("set", "pane-border-format", "#{pane_index} #T") p.cmd("set", "pane-border-status", "top") p.send_keys('ssh %s && exit' % host) p.send_keys('clear') w1.kill_window() w.cmd("set", "synchronize-panes") session.set_option('mouse', True) session.set_option('main-pane-height', 300) w.select_layout(self.layout) session.attach_session()
def test_read_included_specific(): c = sshconf.read_ssh_config(test_config_include_specific) hosts = c.hosts() print("hosts", hosts) assert 'svuincluded' in hosts h = c.host("svuincluded") print(h) print(c.config())
def update_ssh_config(self, path="~/.ssh/config"): """Put the DNS into the ssh config file.""" # Read the config file # import sshconf config = sshconf.read_ssh_config(os.path.expanduser(path)) # In case it doesn't exist # if not config.host(self.instance_name): config.add(self.instance_name) # Add the new DNS # config.set(self.instance_name, Hostname=self.dns) # Write result # config.write(os.path.expanduser(path))
def getHostNames(self, filename): filename = os.path.expanduser(filename) try: conf = read_ssh_config(filename) h = list(conf.hosts()) if "*" in h: h.remove("*") h.sort() return h except FileNotFoundError as e: print("File not found: ", e)
def test_empty(): import tempfile tc = os.path.join(tempfile.gettempdir(), "temp_ssh_config-123") try: c = sshconf.empty_ssh_config_file() c.add("svu33", HostName="ssh33.svu.local", User="******", Port=22) c.write(tc) c2 = sshconf.read_ssh_config(tc) assert 1 == len(c2.hosts()) assert c2.host("svu33")["hostname"] == "ssh33.svu.local" finally: os.remove(tc)
def test_mapping_set_existing_key(): c = sshconf.read_ssh_config(test_config) c.set("svu", Hostname="ssh.svuniversity.ac.in", User="******", proxycommand="nc --help") print(c.config()) assert "Hostname ssh.svuniversity.ac.in" in c.config() assert "User mca" in c.config() assert "ProxyCommand nc --help" in c.config()
def test_mapping_remove_existing_key(): c = sshconf.read_ssh_config(test_config) svu = c.host('svu') print(svu) c.unset("svu", 'proxycommand') print(c.config()) assert "ProxyCommand" not in c.config() svu2 = c.host('svu') assert 'proxycommand' not in svu2 assert 'hostname' in svu2 assert 'port' in svu2
def __init__(self, target, count=4, verbose=False, timeout=10): assert target is not None self.target = target config_path = Path('~/.ssh/config').expanduser() if config_path.exists(): config = read_ssh_config(config_path) try: self.target = config.host(target)['hostname'] except KeyError: pass self.count = count self.verbose = verbose self.timeout = timeout
def set_ssh_config(context, environment, filter='SSH Bastion', tags='public_ip_address'): """ Set Ip Address of Bastion in ssh config file """ hosts = extract_instances_information(context, environment, filter, tags) if len(hosts) == 0: exit("No hosts found - refusing to continue") config = read_ssh_config(ssh_config_file_path) ssh_config_hostname = f"bastion.{environment}.{company}" # set values and write config.set(ssh_config_hostname, Hostname=f"{hosts[0]}") config.write(ssh_config_file_path)
def __host_info(self): info_list = [] config = read_ssh_config(self.config_path) default_user = config.host("*").get('user', 'None') for host in config.hosts(): if host != '*': item = self.__str.format( host, config.host(host)['hostname'], config.host(host).get('user', default_user)) info_list.append(item) self.host_info_sorted = sorted(info_list, key=lambda i: i[0])
def test_set_duplicate_keys(): c = sshconf.read_ssh_config(test_config2) lfs = c.host('foo')['localforward'] assert type(lfs) is list assert len(lfs) == 2 lfs.append("1234 localhost:4321") c.set('foo', localforward=lfs) import tempfile tc = os.path.join(tempfile.gettempdir(), "temp_ssh_config-tudk") try: c.write(tc) d = sshconf.read_ssh_config(tc) host2 = d.host('foo') assert len(host2["localforward"]) == 3 finally: os.remove(tc)
def test_deletehost(self): with self.runner.isolated_filesystem(): self.runner.invoke(lassh, ['init']) self.runner.invoke( lassh, ['addhost', 'snafu', '*****@*****.**', 'henry']) config = read_ssh_config(Path("./lassh.config").resolve()) self.assertEqual(len(config.hosts()), 1) # Now, delete newly added host self.runner.invoke( lassh, ['deletehost', 'snafu'] ) config = read_ssh_config(Path("./lassh.config").resolve()) self.assertEqual(len(config.hosts()), 0) # test removal when hostname doesn't exist self.runner.invoke( lassh, ['deletehost', 'snafu'] ) self.assertEqual(len(config.hosts()), 0)
def addhost(nickname, hostname, user, port, key): """Add a host to your project lassh.config""" # Check for requisite files checkFiles() # Using ssh_conf library, modify hosts config = read_ssh_config(LASSH_CONFIG_PATH.resolve()) # Check for duplicate hosts in local config if nickname in config.hosts(): puts(colored.yellow( 'Found duplicate host with nickname {0}, cancelling' .format(nickname))) return # Check global namespace for duplicate host with open(HOME_LASSH_NAMESPACE_PATH, 'r+') as namespace_file: names = namespace_file.readlines() names = {name.rstrip() for name in names} namespace_file.seek(0) if nickname in names: puts(colored.red(('Found duplicate host nickname in' 'global ssh namespace, cancelling'))) return if (port and key): config.add( nickname, HostName=hostname, User=user, Port=port, IdentityFile=key) elif port: config.add(nickname, HostName=hostname, User=user, Port=port) elif key: config.add(nickname, HostName=hostname, User=user, IdentityFile=key) else: config.add(nickname, HostName=hostname, User=user) # append host to namespace file with open(HOME_LASSH_NAMESPACE_PATH, 'a') as namespace_file: namespace_file.write(''.join([nickname + '\n'])) puts(colored.green('Adding host {0} as {1} with user {2}') .format(hostname, nickname, user)) config.write(LASSH_CONFIG_PATH.resolve())
def ssh_config_file(self): """Returns the configuration for connecting to the ssh server""" if ("ConnectionType" in self.config_handler[ constants.CONFIG_FILE_CONNECTION_SECTION] and "config" == self.config_handler[ constants.CONFIG_FILE_CONNECTION_SECTION]["ConnectionType"] and "SSHConfigFile" in self.config_handler[ constants.CONFIG_FILE_CONNECTION_SECTION] and "ConfigFileHost" in self.config_handler[ constants.CONFIG_FILE_CONNECTION_SECTION]): c = read_ssh_config(expanduser("~/.ssh/config")) return c.host( self.config_handler[constants.CONFIG_FILE_CONNECTION_SECTION] ["ConfigFileHost"]) # print the settings else: return None
def test_mapping_add_new_keys(): c = sshconf.read_ssh_config(test_config) c.add("svu-new", forwardAgent="yes", unknownpropertylikethis="noway", Hostname="ssh.svuni.local", user="******") assert "Host svu-new" in c.config() assert "ForwardAgent yes" in c.config() assert "unknownpropertylikethis noway" in c.config() assert "HostName ssh.svuni.local" in c.config() assert "forwardagent" in c.host("svu-new") assert "unknownpropertylikethis" in c.host("svu-new") assert "hostname" in c.host("svu-new") assert "user" in c.host("svu-new")
def test_remove(): def lines(fn): with open(fn, "r") as f: return len(f.read().splitlines()) import tempfile tc = os.path.join(tempfile.gettempdir(), "temp_ssh_config-123") try: c = sshconf.read_ssh_config(test_config) assert 14 == lines(test_config) c.remove("svu") c.write(tc) assert 9 == lines(tc) assert "# within-host-comment" not in c.config() finally: os.remove(tc)
def test_add(): c = sshconf.read_ssh_config(test_config) c.add("venkateswara", Hostname="venkateswara.onion", User="******", Port=22, ProxyCommand="nc -w 300 -x localhost:9050 %h %p") assert "venkateswara" in c.hosts() assert c.host( "venkateswara")["proxycommand"] == "nc -w 300 -x localhost:9050 %h %p" assert "Host venkateswara" in c.config() with pytest.raises(ValueError): c.add("svu") with pytest.raises(ValueError): c.add("venkateswara")