def importHost(host): sshConfigPath = str(Path.home()) + "/.ssh/config" config = ConfigParser(sshConfigPath) config.load() hostConfig = config.search_host(host) if (hostConfig == []): raise Exception("Host does not exists in %s" % sshConfigPath) return hostConfig
def parse_ssh_config(filename=TMP_SSH_CONF_FILE_NAME, verbose=False): """ Parse the ssh config and return it as list of hosts (dict) :param verbose: :param filename: :return: the ssh conf parsed """ parser = ConfigParser(ssh_config_file=filename) parser.load() return parser.config_data
def __init__(self, module): self.module = module self.params = module.params self.user = self.params.get('user') self.group = self.params.get('group') or self.user self.host = self.params.get('host') self.config_file = self.params.get('ssh_config_file') self.identity_file = self.params['identity_file'] self.check_ssh_config_path() try: self.config = ConfigParser(self.config_file) except FileNotFoundError: self.module.fail_json(msg="Failed to find %s" % self.config_file) self.config.load()
def __init__(self, api_token): self.api_token = api_token self.ssh_id = self.get_ssh_keys() self.ssh_config = StormParser(expanduser('~/.ssh/config')) self.droplet = {} self.droplet_attrs = [ 'name', 'disk', 'image', 'size_slug', 'ip_address' ]
def add_host(self, name, user, hostname, key_file): sconfig = StormParser(expanduser("~/.ssh/config")) sconfig.load() # Remove existig hosts with that name to avoid dupes try: sconfig.delete_host(name) except ValueError: # Host not found pass sconfig.add_host(name, { 'user': user, 'hostname': hostname, 'IdentityFile': key_file, "StrictHostKeyChecking": "no" }) sconfig.write_to_ssh_config()
def main(): args = get_cli_args() ssh_config = StormParser() ssh_config.load() droplets = get_droplets() ssh_config_changed = False for droplet in droplets: ip = droplet.networks["v4"][0]["ip_address"] if host_exists(droplet.name, ssh_config): if args.force_update: ssh_config.update_host(droplet.name, { "hostname": ip, "user": args.user }) with indent(2): puts(get_info(droplet, ip, args)) ssh_config_changed = True else: ssh_config.add_host(droplet.name, { "hostname": ip, "user": args.user }) ssh_config_changed = True with indent(2): puts(get_info(droplet, ip, args)) if ssh_config_changed: ssh_config.write_to_ssh_config() else: with indent(2): puts( colored.red( "all droplets already exists in your ssh config. use --force-update=1 to update." ))
def main(): args = get_cli_args() ssh_config = StormParser() ssh_config.load() droplets = get_droplets() ssh_config_changed = False for droplet in droplets: ip = droplet.networks["v4"][0]["ip_address"] if host_exists(droplet.name, ssh_config): if args.force_update: ssh_config.update_host( droplet.name, {"hostname": ip, "user": args.user} ) with indent(2): puts(get_info(droplet, ip, args)) ssh_config_changed = True else: ssh_config.add_host(droplet.name, {"hostname": ip, "user": args.user}) ssh_config_changed = True with indent(2): puts(get_info(droplet, ip, args)) if ssh_config_changed: ssh_config.write_to_ssh_config() else: with indent(2): puts(colored.red("all droplets already exists in your ssh config. use --force-update=1 to update."))
def remove_host(self, name): sconfig = StormParser(expanduser("~/.ssh/config")) sconfig.load() sconfig.delete_host(name) sconfig.write_to_ssh_config()
def __init__(self, api_token): self.api_token = api_token self.ssh_id = self.get_ssh_keys() self.ssh_config = StormParser(expanduser('~/.ssh/config')) self.droplet = {} self.droplet_attrs = ['name', 'disk', 'image', 'size_slug', 'ip_address']
class DigitalOcean: """Automate Digital Ocean droplet deployment & management""" def __init__(self, api_token): self.api_token = api_token self.ssh_id = self.get_ssh_keys() self.ssh_config = StormParser(expanduser('~/.ssh/config')) self.droplet = {} self.droplet_attrs = ['name', 'disk', 'image', 'size_slug', 'ip_address'] def update_ssh(self): """Update ssh config with new ip address and add missing users""" self.ssh_config.load() users = {'do': 'root', 'do2': 'kaggle'} for host in users.keys(): if self.ssh_config.search_host(host): self.ssh_config.update_host(host, {'user': users[host], 'hostname': self.droplet['ip_address']}) else: self.ssh_config.add_host(host, {'user': users[host], 'hostname': self.droplet['ip_address']}) self.ssh_config.write_to_ssh_config() def update_config_script(self, user=None, password=None, authorized_key='id_rsa', hdf=False): """Make requisite substitutions in base cloud-config file""" with open('cloud-config.txt') as txt: user_data = txt.read() if user and password: user_data = user_data.replace('KAGGLE_CREDENTIALS', ' - export KAGGLE_USER={0}\n - export KAGGLE_PASSWD={1}'.format(user, password)) download_instructions = open('download_instructions.txt').read() if hdf: download_instructions += "\n - python3 -c 'from kaggle_data import data_to_hdf; data_to_hdf()'" user_data = user_data.replace('DATA_DOWNLOAD', download_instructions) else: user_data = user_data.replace('KAGGLE_CREDENTIALS', '') user_data = user_data.replace('DATA_DOWNLOAD', '') if authorized_key: user_data = user_data.replace('SSH_AUTHORIZED_KEYS', 'ssh-authorized-keys:\n - {}'.format( open(expanduser('~/.ssh/{}.pub'.format(authorized_key))).read())) else: user_data.replace('SSH_AUTHORIZED_KEYS', '') return user_data def launch(self, name='kaggle-droplet', region='nyc2', image='ubuntu-16-04-x64', size='512mb', user=None, password=None, authorized_key='id_rsa', hdf=False): """Launch DigitalOcean droplet instance""" user_data = self.update_config_script(user=user, password=password, authorized_key=authorized_key, hdf=hdf) droplet = Droplet(token=self.api_token, name=name, region=region, image=image, size_slug=size, backups=False, ssh_keys=self.ssh_id, user_data=user_data) droplet.create() self.droplet['id'] = droplet.id while not self.droplet.get('ip_address', None): self.droplet['ip_address'] = droplet.load().ip_address self.update_ssh() pprint.pprint(('Name: {}'.format(droplet.name), 'Image: {}'.format(droplet.image.get('slug')), 'Memory: {}'.format(droplet.size_slug), 'Disk Size: {}'.format(droplet.disk), 'IP Address: {}'.format(droplet.ip_address))) def get_droplets(self): """Get active droplets""" manager = Manager(token=self.api_token) my_droplets = manager.get_all_droplets() return my_droplets def destroy(self): """Destroy all active droplets""" my_droplets = self.get_droplets() for droplet in my_droplets: droplet.destroy() def get_ssh_keys(self): """Get ssh keys stored with DigitalOcean""" do_ssh_url = 'https://api.digitalocean.com/v2/account/keys' headers = dict(Authorization='Bearer {}'.format(self.api_token)) response = requests.get(url=do_ssh_url, headers=headers) ssh_keys = [] for ssh_key in response.json().get('ssh_keys'): ssh_keys.append(ssh_key.get('id')) return ssh_keys
class SSHConfig(): def __init__(self, module): self.module = module self.params = module.params self.user = self.params.get('user') self.group = self.params.get('group') or self.user self.host = self.params.get('host') self.config_file = self.params.get('ssh_config_file') self.identity_file = self.params['identity_file'] self.check_ssh_config_path() try: self.config = ConfigParser(self.config_file) except FileNotFoundError: self.module.fail_json(msg="Failed to find %s" % self.config_file) self.config.load() def check_ssh_config_path(self): if self.user: self.config_file = os.path.join( os.path.expanduser('~%s' % self.user), '.ssh', 'config') elif self.config_file is None: self.config_file = '/etc/ssh/ssh_config' # See if the identity file exists or not, relative to the config file if os.path.exists(self.config_file) and self.identity_file is not None: dirname = os.path.dirname(self.config_file) self.identity_file = os.path.join(dirname, self.identity_file) if not os.path.exists(self.identity_file): self.module.fail_json(msg='IdentityFile %s does not exist' % self.params['identity_file']) def ensure_state(self): hosts_result = self.config.search_host(self.host) state = self.params['state'] args = dict( hostname=self.params.get('hostname'), port=self.params.get('port'), identity_file=self.params.get('identity_file'), user=self.params.get('remote_user'), strict_host_key_checking=self.params.get( 'strict_host_key_checking'), user_known_hosts_file=self.params.get('user_known_hosts_file'), proxycommand=self.params.get('proxycommand'), ) config_changed = False hosts_changed = [] hosts_change_diff = [] hosts_removed = [] hosts_added = [] hosts_result = [ host for host in hosts_result if host['host'] == self.host ] if hosts_result: for host in hosts_result: if state == 'absent': # Delete host from the configuration config_changed = True hosts_removed.append(host['host']) self.config.delete_host(host['host']) else: # Update host in the configuration changed, options = self.change_host( host['options'], **args) if changed: config_changed = True self.config.update_host(host['host'], options) hosts_changed.append(host['host']) hosts_change_diff.append({ host['host']: { 'old': host['options'], 'new': options, } }) elif state == 'present': changed, options = self.change_host(dict(), **args) if changed: config_changed = True hosts_added.append(self.host) self.config.add_host(self.host, options) if config_changed and not self.module.check_mode: try: self.config.write_to_ssh_config() except PermissionError as perm_exec: self.module.fail_json( msg="Failed to write to %s due to permission issue: %s" % (self.config_file, to_native(perm_exec))) # Make sure we set the permission perm_mode = '0600' if self.config_file == '/etc/ssh/ssh_config': perm_mode = '0644' self.module.set_mode_if_different(self.config_file, perm_mode, False) # Make sure the file is owned by the right user and group self.module.set_owner_if_different(self.config_file, self.user, False) self.module.set_group_if_different(self.config_file, self.group, False) self.module.exit_json(changed=config_changed, hosts_changed=hosts_changed, hosts_removed=hosts_removed, hosts_change_diff=hosts_change_diff, hosts_added=hosts_added) @staticmethod def change_host(options, **kwargs): options = deepcopy(options) changed = False for k, v in kwargs.items(): if '_' in k: k = k.replace('_', '') if not v: if options.get(k): del options[k] changed = True elif options.get(k) != v and not (isinstance(options.get(k), list) and v in options.get(k)): options[k] = v changed = True return changed, options
class DigitalOcean: """Automate Digital Ocean droplet deployment & management""" def __init__(self, api_token): self.api_token = api_token self.ssh_id = self.get_ssh_keys() self.ssh_config = StormParser(expanduser('~/.ssh/config')) self.droplet = {} self.droplet_attrs = [ 'name', 'disk', 'image', 'size_slug', 'ip_address' ] def update_ssh(self): """Update ssh config with new ip address and add missing users""" self.ssh_config.load() users = {'do': 'root', 'do2': 'kaggle'} for host in users.keys(): if self.ssh_config.search_host(host): self.ssh_config.update_host( host, { 'user': users[host], 'hostname': self.droplet['ip_address'] }) else: self.ssh_config.add_host(host, { 'user': users[host], 'hostname': self.droplet['ip_address'] }) self.ssh_config.write_to_ssh_config() def update_config_script(self, user=None, password=None, authorized_key='id_rsa', hdf=False): """Make requisite substitutions in base cloud-config file""" with open('cloud-config.txt') as txt: user_data = txt.read() if user and password: user_data = user_data.replace( 'KAGGLE_CREDENTIALS', ' - export KAGGLE_USER={0}\n - export KAGGLE_PASSWD={1}'. format(user, password)) download_instructions = open('download_instructions.txt').read() if hdf: download_instructions += "\n - python3 -c 'from kaggle_data import data_to_hdf; data_to_hdf()'" user_data = user_data.replace('DATA_DOWNLOAD', download_instructions) else: user_data = user_data.replace('KAGGLE_CREDENTIALS', '') user_data = user_data.replace('DATA_DOWNLOAD', '') if authorized_key: user_data = user_data.replace( 'SSH_AUTHORIZED_KEYS', 'ssh-authorized-keys:\n - {}'.format( open(expanduser( '~/.ssh/{}.pub'.format(authorized_key))).read())) else: user_data.replace('SSH_AUTHORIZED_KEYS', '') return user_data def launch(self, name='kaggle-droplet', region='nyc2', image='ubuntu-16-04-x64', size='512mb', user=None, password=None, authorized_key='id_rsa', hdf=False): """Launch DigitalOcean droplet instance""" user_data = self.update_config_script(user=user, password=password, authorized_key=authorized_key, hdf=hdf) droplet = Droplet(token=self.api_token, name=name, region=region, image=image, size_slug=size, backups=False, ssh_keys=self.ssh_id, user_data=user_data) droplet.create() self.droplet['id'] = droplet.id while not self.droplet.get('ip_address', None): self.droplet['ip_address'] = droplet.load().ip_address self.update_ssh() pprint.pprint(('Name: {}'.format(droplet.name), 'Image: {}'.format( droplet.image.get('slug')), 'Memory: {}'.format(droplet.size_slug), 'Disk Size: {}'.format(droplet.disk), 'IP Address: {}'.format(droplet.ip_address))) def get_droplets(self): """Get active droplets""" manager = Manager(token=self.api_token) my_droplets = manager.get_all_droplets() return my_droplets def destroy(self): """Destroy all active droplets""" my_droplets = self.get_droplets() for droplet in my_droplets: droplet.destroy() def get_ssh_keys(self): """Get ssh keys stored with DigitalOcean""" do_ssh_url = 'https://api.digitalocean.com/v2/account/keys' headers = dict(Authorization='Bearer {}'.format(self.api_token)) response = requests.get(url=do_ssh_url, headers=headers) ssh_keys = [] for ssh_key in response.json().get('ssh_keys'): ssh_keys.append(ssh_key.get('id')) return ssh_keys