%PDF- %PDF-
Direktori : /usr/lib/python2.7/site-packages/salt/roster/ |
Current File : //usr/lib/python2.7/site-packages/salt/roster/terraform.py |
# -*- coding: utf-8 -*- ''' Dynamic roster from terraform current state =========================================== This roster module allows you dynamically generate the roster from the terraform resources defined with the `Terraform Salt`_ provider. It exposes all salt_host resources with the same attributes to the salt-ssh roster, making it completely independent of the type of terraform resource, and providing the integration using terraform constructs with interpolation. Basic Example ------------- Given a simple salt-ssh tree with a Saltfile: .. code-block:: yaml salt-ssh: config_dir: etc/salt max_procs: 30 wipe_ssh: True and ``etc/salt/master``: .. code-block:: yaml root_dir: . file_roots: base: - srv/salt pillar_roots: base: - srv/pillar roster: terraform In the same folder as your ``Saltfile``, create terraform file with resources like cloud instances, virtual machines, etc. For every single one of those that you want to manage with Salt, create a ``salt_host`` resource: .. code-block:: text resource "salt_host" "dbminion" { salt_id = "dbserver" host = "${libvirt_domain.vm-db.network_interface.0.addresses.0}" user = "root" passwd = "linux" } You can use the count attribute to create multiple roster entries with a single definition. Please refer to the `Terraform Salt`_ provider for more detailed examples. .. _Terraform Salt: https://github.com/dmacvicar/terraform-provider-salt ''' # Import Python libs from __future__ import absolute_import, unicode_literals import logging import os.path # Import Salt libs import salt.utils.files import salt.utils.json log = logging.getLogger(__name__) TF_OUTPUT_PREFIX = 'salt.roster.' TF_ROSTER_ATTRS = {'host': 's', 'user': 's', 'passwd': 's', 'port': 'i', 'sudo': 'b', 'sudo_user': 's', 'tty': 'b', 'priv': 's', 'timeout': 'i', 'minion_opts': 'm', 'thin_dir': 's', 'cmd_umask': 'i'} MINION_ID = 'salt_id' def _handle_salt_host_resource(resource): ''' Handles salt_host resources. See https://github.com/dmacvicar/terraform-provider-salt Returns roster attributes for the resource or None ''' ret = {} attrs = resource.get('primary', {}).get('attributes', {}) ret[MINION_ID] = attrs.get(MINION_ID) valid_attrs = set(attrs.keys()).intersection(TF_ROSTER_ATTRS.keys()) for attr in valid_attrs: ret[attr] = _cast_output_to_type(attrs.get(attr), TF_ROSTER_ATTRS.get(attr)) return ret def _add_ssh_key(ret): ''' Setups the salt-ssh minion to be accessed with salt-ssh default key ''' priv = None if __opts__.get('ssh_use_home_key') and os.path.isfile(os.path.expanduser('~/.ssh/id_rsa')): priv = os.path.expanduser('~/.ssh/id_rsa') else: priv = __opts__.get( 'ssh_priv', os.path.abspath(os.path.join( __opts__['pki_dir'], 'ssh', 'salt-ssh.rsa' )) ) if priv and os.path.isfile(priv): ret['priv'] = priv def _cast_output_to_type(value, typ): '''cast the value depending on the terraform type''' if typ == 'b': return bool(value) if typ == 'i': return int(value) return value def _parse_state_file(state_file_path='terraform.tfstate'): ''' Parses the terraform state file passing different resource types to the right handler ''' ret = {} with salt.utils.files.fopen(state_file_path, 'r') as fh_: tfstate = salt.utils.json.load(fh_) modules = tfstate.get('modules') if not modules: log.error('Malformed tfstate file. No modules found') return ret for module in modules: resources = module.get('resources', []) for resource_name, resource in salt.ext.six.iteritems(resources): roster_entry = None if resource['type'] == 'salt_host': roster_entry = _handle_salt_host_resource(resource) if not roster_entry: continue minion_id = roster_entry.get(MINION_ID, resource.get('id')) if not minion_id: continue if MINION_ID in roster_entry: del roster_entry[MINION_ID] _add_ssh_key(roster_entry) ret[minion_id] = roster_entry return ret def targets(tgt, tgt_type='glob', **kwargs): # pylint: disable=W0613 ''' Returns the roster from the terraform state file, checks opts for location, but defaults to terraform.tfstate ''' roster_file = os.path.abspath('terraform.tfstate') if __opts__.get('roster_file'): roster_file = os.path.abspath(__opts__['roster_file']) if not os.path.isfile(roster_file): log.error("Can't find terraform state file '%s'", roster_file) return {} log.debug('terraform roster: using %s state file', roster_file) if not roster_file.endswith('.tfstate'): log.error("Terraform roster can only be used with terraform state files") return {} raw = _parse_state_file(roster_file) log.debug('%s hosts in terraform state file', len(raw)) return __utils__['roster_matcher.targets'](raw, tgt, tgt_type, 'ipv4')