def start(self): ''' Execute this method to start up a syndic. ''' verify_env([ self.opts['pki_dir'], self.opts['cachedir'], os.path.dirname(self.opts['log_file']), ]) import salt.log salt.log.setup_logfile_logger(self.opts['log_file'], self.opts['log_level']) for name, level in self.opts['log_granular_levels'].iteritems(): salt.log.set_logger_level(name, level) import logging # Late import so logging works correctly import salt.minion log = logging.getLogger(__name__) if self.cli['daemon']: # Late import so logging works correctly import salt.utils salt.utils.daemonize() set_pidfile(self.cli['pidfile']) if check_user(self.opts['user'], log): try: syndic = salt.minion.Syndic(self.opts) syndic.tune_in() except KeyboardInterrupt: log.warn('Stopping the Salt Syndic Minion') raise SystemExit('\nExiting on Ctrl-c')
def has_battery(): ''' Return true if a battery exists. ''' # We need to have the `acpi` binary installed to avoid having to do the # old vs new acpi detection our selves. acpi = salt.utils.which('acpi') if acpi is None or acpi == "": return {} # call ACPI binary: `acpi -b` to return the battery status. As long as the # binary exists, it will return either the status of all batteries it knows # about in the following format: # 'Battery X: Full, YY%' or 'No support for device type: power_supply' # In the former, we return True, the latter we return False. I hope it's # obvious why. ;) result = salt.modules.cmdmod._run_quiet('acpi -b') if 'No support for device type' in result: return {'has_battery': 0} elif 'Battery ' in result: return {'has_battery': 1} else: log.warn('Unexpected output from `acpi -b`: {0}'.format(result)) return {}
def start(self): ''' Execute this method to start up a minion. ''' verify_env([ self.opts['pki_dir'], self.opts['cachedir'], self.opts['extension_modules'], os.path.dirname(self.opts['log_file']), ]) import salt.log salt.log.setup_logfile_logger(self.opts['log_file'], self.opts['log_level']) for name, level in self.opts['log_granular_levels'].iteritems(): salt.log.set_logger_level(name, level) import logging # Late import so logging works correctly import salt.minion log = logging.getLogger(__name__) if self.cli['daemon']: # Late import so logging works correctly import salt.utils # If the minion key has not been accepted, then Salt enters a loop # waiting for it, if we daemonize later then the minion cound halt # the boot process waiting for a key to be accepted on the master. # This is the latest safe place to daemonize salt.utils.daemonize() minion = salt.minion.Minion(self.opts) set_pidfile(self.cli['pidfile']) if check_user(self.opts['user'], log): try: minion.tune_in() except KeyboardInterrupt: log.warn('Stopping the Salt Minion') raise SystemExit('\nExiting on Ctrl-c')
def include_config(include, opts, orig_path, verbose): ''' Parses extra configuration file(s) specified in an include list in the main config file. ''' # Protect against empty option if not include: return opts if isinstance(include, str): include = [include] for path in include: if not os.path.isabs(path): path = os.path.join(os.path.dirname(orig_path), path) # Catch situation where user typos path in config; also warns for # empty include dir (which might be by design) if len(glob.glob(path)) == 0: msg = "Warning parsing configuration file: 'include' path/glob '{0}' matches no files" if verbose: log.warn(msg.format(path)) for fn_ in glob.glob(path): try: opts.update(_read_conf_file(fn_)) except Exception as e: msg = 'Error parsing configuration file: {0} - {1}' log.warn(msg.format(fn_, e)) return opts
def ext_pillar( minion_id, # pylint: disable=W0613 pillar, # pylint: disable=W0613 config_file): ''' Execute LDAP searches and return the aggregated data ''' if os.path.isfile(config_file): try: #open(config_file, 'r') as raw_config: config = _render_template(config_file) or {} opts = yaml.safe_load(config) or {} opts['conf_file'] = config_file except Exception as err: import salt.log msg = 'Error parsing configuration file: {0} - {1}' if salt.log.is_console_configured(): log.warn(msg.format(config_file, err)) else: print(msg.format(config_file, err)) else: log.debug('Missing configuration file: {0}'.format(config_file)) data = {} for source in opts['search_order']: config = opts[source] result = _do_search(config) print('source {0} got result {1}'.format(source, result)) if result: data = _result_to_dict(data, result, config) return data
def has_battery(): ''' Return true if a battery exists. ''' # We need to have the `acpi` binary installed to avoid having to do the # old vs new acpi detection our selves. acpi = salt.utils.which('acpi') if acpi == None or acpi == "": return {} # call ACPI binary: `acpi -b` to return the battery status. As long as the # binary exists, it will return either the status of all batteries it knows # about in the following format: # 'Battery X: Full, YY%' or 'No support for device type: power_supply' # In the former, we return True, the latter we return False. I hope it's # obvious why. ;) result = salt.modules.cmdmod._run_quiet('acpi -b') if 'No support for device type' in result: return {'has_battery': 0} elif 'Battery ' in result: return {'has_battery': 1} else: log.warn('Unexpected output from `acpi -b`: %s' % result) return {}
def load_config(opts, path, env_var): ''' Attempts to update ``opts`` dict by parsing either the file described by ``path`` or the environment variable described by ``env_var`` as YAML. ''' if not path or not os.path.isfile(path): path = os.environ.get(env_var, path) # If the configuration file is missing, attempt to copy the template, # after removing the first header line. if not os.path.isfile(path): template = '{0}.template'.format(path) if os.path.isfile(template): with open(path, 'w') as out: with open(template, 'r') as f: f.readline() # skip first line out.write(f.read()) if os.path.isfile(path): try: opts.update(_read_conf_file(path)) opts['conf_file'] = path except Exception as e: import salt.log msg = 'Error parsing configuration file: {0} - {1}' if salt.log.is_console_configured(): log.warn(msg.format(path, e)) else: print(msg.format(path, e)) else: log.debug('Missing configuration file: {0}'.format(path))
def mine(tgt=None, expr_form='glob', outputter=None, **kwargs): ''' Return cached mine data of the targeted minions CLI Example: .. code-block:: bash salt-run cache.mine ''' deprecated_minion = kwargs.get('minion', None) if tgt is None and deprecated_minion is None: log.warn("DEPRECATION WARNING: {0}".format(deprecation_warning)) tgt = '*' # targat all minions for backward compatibility elif tgt is None and isinstance(deprecated_minion, string_types): log.warn("DEPRECATION WARNING: {0}".format(deprecation_warning)) tgt = deprecated_minion elif tgt is None: return {} pillar_util = salt.utils.master.MasterPillarUtil(tgt, expr_form, use_cached_grains=False, grains_fallback=False, use_cached_pillar=False, pillar_fallback=False, opts=__opts__) cached_mine = pillar_util.get_cached_mine_data() salt.output.display_output(cached_mine, outputter, __opts__)
def pillar(tgt=None, expr_form='glob', outputter=None, **kwargs): ''' Return cached pillars of the targeted minions CLI Example: .. code-block:: bash salt-run cache.pillar ''' deprecated_minion = kwargs.get('minion', None) if tgt is None and deprecated_minion is None: log.warn("DEPRECATION WARNING: {0}".format(DEPRECATION_WARNING)) tgt = '*' # targat all minions for backward compatibility elif tgt is None and isinstance(deprecated_minion, string_types): log.warn("DEPRECATION WARNING: {0}".format(DEPRECATION_WARNING)) tgt = deprecated_minion elif tgt is None: return {} pillar_util = salt.utils.master.MasterPillarUtil(tgt, expr_form, use_cached_grains=True, grains_fallback=False, use_cached_pillar=True, pillar_fallback=False, opts=__opts__) cached_pillar = pillar_util.get_minion_pillar() if outputter: return {'outputter': outputter, 'data': cached_pillar} else: return cached_pillar
def start(self): ''' Execute this method to start up a syndic. ''' verify_env([self.opts['pki_dir'], self.opts['cachedir'], os.path.dirname(self.opts['log_file']), ]) import salt.log salt.log.setup_logfile_logger( self.opts['log_file'], self.opts['log_level'] ) for name, level in self.opts['log_granular_levels'].iteritems(): salt.log.set_logger_level(name, level) import logging # Late import so logging works correctly import salt.minion log = logging.getLogger(__name__) if check_user(self.opts['user'], log): try: syndic = salt.minion.Syndic(self.opts) if self.cli['daemon']: # Late import so logging works correctly import salt.utils salt.utils.daemonize() set_pidfile(self.cli['pidfile']) syndic.tune_in() except KeyboardInterrupt: log.warn('Stopping the Salt Syndic Minion') raise SystemExit('\nExiting on Ctrl-c')
def ext_pillar(minion_id, # pylint: disable=W0613 pillar, # pylint: disable=W0613 config_file): ''' Execute LDAP searches and return the aggregated data ''' if os.path.isfile(config_file): try: #open(config_file, 'r') as raw_config: config = _render_template(config_file) or {} opts = yaml.safe_load(config) or {} opts['conf_file'] = config_file except Exception as err: import salt.log msg = 'Error parsing configuration file: {0} - {1}' if salt.log.is_console_configured(): log.warn(msg.format(config_file, err)) else: print(msg.format(config_file, err)) else: log.debug('Missing configuration file: {0}'.format(config_file)) data = {} for source in opts['search_order']: config = opts[source] result = _do_search(config) print('source {0} got result {1}'.format(source, result)) if result: data = _result_to_dict(data, result, config) return data
def mine(tgt=None, expr_form='glob', **kwargs): ''' Return cached mine data of the targeted minions CLI Example: .. code-block:: bash salt-run cache.mine ''' deprecated_minion = kwargs.get('minion', None) if tgt is None and deprecated_minion is None: log.warn("DEPRECATION WARNING: {0}".format(deprecation_warning)) tgt = '*' # targat all minions for backward compatibility elif tgt is None and isinstance(deprecated_minion, string_types): log.warn("DEPRECATION WARNING: {0}".format(deprecation_warning)) tgt = deprecated_minion elif tgt is None: return {} pillar_util = salt.utils.master.MasterPillarUtil(tgt, expr_form, use_cached_grains=False, grains_fallback=False, use_cached_pillar=False, pillar_fallback=False, opts=__opts__) cached_mine = pillar_util.get_cached_mine_data() salt.output.display_output(cached_mine, None, __opts__)
def start(self): ''' Execute this method to start up a minion. ''' verify_env([self.opts['pki_dir'], self.opts['cachedir'], self.opts['extension_modules'], os.path.dirname(self.opts['log_file']), ]) import salt.log salt.log.setup_logfile_logger( self.opts['log_file'], self.opts['log_level'] ) for name, level in self.opts['log_granular_levels'].iteritems(): salt.log.set_logger_level(name, level) import logging # Late import so logging works correctly import salt.minion log = logging.getLogger(__name__) if self.cli['daemon']: # Late import so logging works correctly import salt.utils # If the minion key has not been accepted, then Salt enters a loop # waiting for it, if we daemonize later then the minion cound halt # the boot process waiting for a key to be accepted on the master. # This is the latest safe place to daemonize salt.utils.daemonize() minion = salt.minion.Minion(self.opts) set_pidfile(self.cli['pidfile']) if check_user(self.opts['user'], log): try: minion.tune_in() except KeyboardInterrupt: log.warn('Stopping the Salt Minion') raise SystemExit('\nExiting on Ctrl-c')
def _linux_gpu_data(): ''' num_gpus: int gpus: - vendor: nvidia|amd|ati|... model: string ''' # dominant gpu vendors to search for (MUST be lowercase for matching below) known_vendors = ['nvidia', 'amd', 'ati', 'intel'] devs = [] try: lspci_out = __salt__['cmd.run']('lspci -vmm') cur_dev = {} error = False for line in lspci_out.splitlines(): # check for record-separating empty lines if line == '': if cur_dev.get('Class', '') == 'VGA compatible controller': devs.append(cur_dev) # XXX; may also need to search for "3D controller" cur_dev = {} continue if re.match(r'^\w+:\s+.*', line): key, val = line.split(':', 1) cur_dev[key.strip()] = val.strip() else: error = True log.debug('Unexpected lspci output: \'{0}\''.format(line)) if error: log.warn( 'Error loading grains, unexpected linux_gpu_data output, ' 'check that you have a valid shell configured and ' 'permissions to run lspci command' ) except OSError: pass gpus = [] for gpu in devs: vendor_strings = gpu['Vendor'].lower().split() # default vendor to 'unknown', overwrite if we match a known one vendor = 'unknown' for name in known_vendors: # search for an 'expected' vendor name in the list of strings if name in vendor_strings: vendor = name break gpus.append({'vendor': vendor, 'model': gpu['Device']}) grains = {} grains['num_gpus'] = len(gpus) grains['gpus'] = gpus return grains
def _get_live_minion_pillar(self, minion_id=None, minion_grains=None): # Returns a dict of pillar data for one minion if minion_id is None: return {} if not minion_grains: log.warn( 'Cannot get pillar data for {0}: no grains supplied.'.format( minion_id)) return {} log.debug('Getting live pillar for {0}'.format(minion_id)) pillar = salt.pillar.Pillar(self.opts, minion_grains, minion_id, self.saltenv, self.opts['ext_pillar']) log.debug('Compiling pillar for {0}'.format(minion_id)) ret = pillar.compile_pillar() return ret
def _get_live_minion_pillar(self, minion_id=None, minion_grains=None): # Returns a dict of pillar data for one minion if minion_id == None: return {} if not minion_grains: log.warn('Cannot get pillar data for {0}: no grains supplied.'.format(minion_id)) return {} log.debug('Getting live pillar for {0}'.format(minion_id)) pillar = salt.pillar.Pillar( self.opts, minion_grains, minion_id, self.env, self.opts['ext_pillar']) log.debug('Compiling pillar for {0}'.format(minion_id)) ret = pillar.compile_pillar() return ret
def include_config(include, orig_path, verbose): ''' Parses extra configuration file(s) specified in an include list in the main config file. ''' # Protect against empty option if not include: return {} if orig_path is None: # When the passed path is None, we just want the configuration # defaults, not actually loading the whole configuration. return {} if isinstance(include, str): include = [include] configuration = {} for path in include: # Allow for includes like ~/foo path = os.path.expanduser(path) if not os.path.isabs(path): path = os.path.join(os.path.dirname(orig_path), path) # Catch situation where user typos path in configuration; also warns # for empty include directory (which might be by design) if len(glob.glob(path)) == 0: if verbose: log.warn( 'Warning parsing configuration file: "include" path/glob ' '"{0}" matches no files'.format(path) ) for fn_ in sorted(glob.glob(path)): try: log.debug('Including configuration from {0}'.format(fn_)) configuration.update(_read_conf_file(fn_)) except Exception as err: log.warn( 'Error parsing configuration file: {0} - {1}'.format( fn_, err ) ) return configuration
def grains(tgt=None, expr_form='glob', **kwargs): ''' Return cached grains of the targeted minions ''' deprecated_minion = kwargs.get('minion', None) if tgt is None and deprecated_minion is None: log.warn("DEPRECATION WARNING: {0}".format(deprecation_warning)) tgt = '*' # targat all minions for backward compatibility elif tgt is None and isinstance(deprecated_minion, string_types): log.warn("DEPRECATION WARNING: {0}".format(deprecation_warning)) tgt = deprecated_minion elif tgt is None: return {} pillar_util = salt.utils.master.MasterPillarUtil(tgt, expr_form, use_cached_grains=True, grains_fallback=False, opts=__opts__) cached_grains = pillar_util.get_minion_grains() salt.output.display_output(cached_grains, None, __opts__) return cached_grains
def include_config(include, orig_path, verbose): ''' Parses extra configuration file(s) specified in an include list in the main config file. ''' # Protect against empty option if not include: return {} if orig_path is None: # When the passed path is None, we just want the configuration # defaults, not actually loading the whole configuration. return {} if isinstance(include, str): include = [include] configuration = {} for path in include: # Allow for includes like ~/foo path = os.path.expanduser(path) if not os.path.isabs(path): path = os.path.join(os.path.dirname(orig_path), path) # Catch situation where user typos path in configuration; also warns # for empty include directory (which might be by design) if len(glob.glob(path)) == 0: if verbose: log.warn( 'Warning parsing configuration file: "include" path/glob ' '{0!r} matches no files'.format(path)) for fn_ in sorted(glob.glob(path)): try: log.debug('Including configuration from {0!r}'.format(fn_)) configuration.update(_read_conf_file(fn_)) except Exception as err: log.warn('Error parsing configuration file: {0} - {1}'.format( fn_, err)) return configuration
def resolve_dns(opts): ''' Resolves the master_ip and master_uri options ''' ret = {} check_dns = True if opts.get('file_client', 'remote') == 'local' and check_dns: check_dns = False if check_dns is True: # Because I import salt.log below I need to re-import salt.utils here import salt.utils try: ret['master_ip'] = salt.utils.dns_check(opts['master'], True) except SaltClientError: if opts['retry_dns']: while True: import salt.log msg = ('Master hostname: {0} not found. Retrying in {1} ' 'seconds').format(opts['master'], opts['retry_dns']) if salt.log.is_console_configured(): log.warn(msg) else: print('WARNING: {0}'.format(msg)) time.sleep(opts['retry_dns']) try: ret['master_ip'] = salt.utils.dns_check( opts['master'], True ) break except SaltClientError: pass else: ret['master_ip'] = '127.0.0.1' else: ret['master_ip'] = '127.0.0.1' ret['master_uri'] = 'tcp://{ip}:{port}'.format(ip=ret['master_ip'], port=opts['master_port']) return ret
def load_config(path, env_var): ''' Returns configuration dict from parsing either the file described by ``path`` or the environment variable described by ``env_var`` as YAML. ''' if path is None: # When the passed path is None, we just want the configuration # defaults, not actually loading the whole configuration. return {} if not path or not os.path.isfile(path): path = os.environ.get(env_var, path) # If the configuration file is missing, attempt to copy the template, # after removing the first header line. if not os.path.isfile(path): template = '{0}.template'.format(path) if os.path.isfile(template): import salt.utils # TODO: Need to re-import, need to find out why log.debug('Writing {0} based on {1}'.format(path, template)) with salt.utils.fopen(path, 'w') as out: with salt.utils.fopen(template, 'r') as ifile: ifile.readline() # skip first line out.write(ifile.read()) if os.path.isfile(path): try: opts = _read_conf_file(path) opts['conf_file'] = path return opts except Exception as err: import salt.log msg = 'Error parsing configuration file: {0} - {1}' if salt.log.is_console_configured(): log.warn(msg.format(path, err)) else: print(msg.format(path, err)) else: log.debug('Missing configuration file: {0}'.format(path)) return {}
def resolve_dns(opts): ''' Resolves the master_ip and master_uri options ''' ret = {} check_dns = True if opts.get('file_client', 'remote') == 'local' and check_dns: check_dns = False if check_dns is True: # Because I import salt.log below I need to re-import salt.utils here import salt.utils try: ret['master_ip'] = salt.utils.dns_check(opts['master'], True) except SaltClientError: if opts['retry_dns']: while True: import salt.log msg = ('Master hostname: {0} not found. Retrying in {1} ' 'seconds').format(opts['master'], opts['retry_dns']) if salt.log.is_console_configured(): log.warn(msg) else: print('WARNING: {0}'.format(msg)) time.sleep(opts['retry_dns']) try: ret['master_ip'] = salt.utils.dns_check( opts['master'], True) break except SaltClientError: pass else: ret['master_ip'] = '127.0.0.1' else: ret['master_ip'] = '127.0.0.1' ret['master_uri'] = 'tcp://{ip}:{port}'.format(ip=ret['master_ip'], port=opts['master_port']) return ret
def load_config(path, env_var): ''' Returns configuration dict from parsing either the file described by ``path`` or the environment variable described by ``env_var`` as YAML. ''' if path is None: # When the passed path is None, we just want the configuration # defaults, not actually loading the whole configuration. return {} if not path or not os.path.isfile(path): path = os.environ.get(env_var, path) # If the configuration file is missing, attempt to copy the template, # after removing the first header line. if not os.path.isfile(path): template = '{0}.template'.format(path) if os.path.isfile(template): import salt.utils # TODO: Need to re-import, need to find out why with salt.utils.fopen(path, 'w') as out: with salt.utils.fopen(template, 'r') as ifile: ifile.readline() # skip first line out.write(ifile.read()) if os.path.isfile(path): try: opts = _read_conf_file(path) opts['conf_file'] = path return opts except Exception as err: import salt.log msg = 'Error parsing configuration file: {0} - {1}' if salt.log.is_console_configured(): log.warn(msg.format(path, err)) else: print(msg.format(path, err)) else: log.debug('Missing configuration file: {0}'.format(path)) return {}
def _virtual(osdata): ''' Returns what type of virtual hardware is under the hood, kvm or physical ''' # This is going to be a monster, if you are running a vm you can test this # grain with please submit patches! # Provides: # virtual # virtual_subtype grains = {'virtual': 'physical'} for command in ('dmidecode', 'lspci', 'dmesg'): args = [] if osdata['kernel'] == 'Darwin': command = 'system_profiler' args = ['SPDisplaysDataType'] cmd = salt.utils.which(command) if not cmd: continue cmd = '%s %s' % (command, ' '.join(args)) ret = __salt__['cmd.run_all'](cmd) if ret['retcode'] > 0: if salt.log.is_logging_configured(): if salt.utils.is_windows(): continue log.warn( 'Although \'{0}\' was found in path, the current user ' 'cannot execute it. Grains output might not be ' 'accurate.'.format(command) ) continue output = ret['stdout'] if command == "system_profiler": macoutput = output.lower() if '0x1ab8' in macoutput: grains['virtual'] = 'Parallels' if 'parallels' in macoutput: grains['virtual'] = 'Parallels' if 'vmware' in macoutput: grains['virtual'] = 'VMware' if '0x15ad' in macoutput: grains['virtual'] = 'VMware' if 'virtualbox' in macoutput: grains['virtual'] = 'VirtualBox' # Break out of the loop so the next log message is not issued break elif command == 'dmidecode' or command == 'dmesg': # Product Name: VirtualBox if 'Vendor: QEMU' in output: # FIXME: Make this detect between kvm or qemu grains['virtual'] = 'kvm' if 'Vendor: Bochs' in output: grains['virtual'] = 'kvm' # Product Name: (oVirt) www.ovirt.org # Red Hat Community virtualization Project based on kvm elif 'Manufacturer: oVirt' in output: grains['virtual'] = 'kvm' elif 'VirtualBox' in output: grains['virtual'] = 'VirtualBox' # Product Name: VMware Virtual Platform elif 'VMware' in output: grains['virtual'] = 'VMware' # Manufacturer: Microsoft Corporation # Product Name: Virtual Machine elif ': Microsoft' in output and 'Virtual Machine' in output: grains['virtual'] = 'VirtualPC' # Manufacturer: Parallels Software International Inc. elif 'Parallels Software' in output: grains['virtual'] = 'Parallels' # Break out of the loop, lspci parsing is not necessary break elif command == 'lspci': # dmidecode not available or the user does not have the necessary # permissions model = output.lower() if 'vmware' in model: grains['virtual'] = 'VMware' # 00:04.0 System peripheral: InnoTek Systemberatung GmbH VirtualBox Guest Service elif 'virtualbox' in model: grains['virtual'] = 'VirtualBox' elif 'qemu' in model: grains['virtual'] = 'kvm' elif 'virtio' in model: grains['virtual'] = 'kvm' # Break out of the loop so the next log message is not issued break else: log.warn( 'The tools \'dmidecode\', \'lspci\' and \'dmesg\' failed to execute ' 'because they do not exist on the system of the user running ' 'this instance or the user does not have the necessary permissions ' 'to execute them. Grains output might not be accurate.' ) choices = ('Linux', 'OpenBSD', 'HP-UX') isdir = os.path.isdir sysctl = salt.utils.which('sysctl') if osdata['kernel'] in choices: if isdir('/proc/vz'): if os.path.isfile('/proc/vz/version'): grains['virtual'] = 'openvzhn' else: grains['virtual'] = 'openvzve' elif isdir('/proc/sys/xen') or isdir('/sys/bus/xen') or isdir('/proc/xen'): if os.path.isfile('/proc/xen/xsd_kva'): # Tested on CentOS 5.3 / 2.6.18-194.26.1.el5xen # Tested on CentOS 5.4 / 2.6.18-164.15.1.el5xen grains['virtual_subtype'] = 'Xen Dom0' else: if grains.get('productname', '') == 'HVM domU': # Requires dmidecode! grains['virtual_subtype'] = 'Xen HVM DomU' elif os.path.isfile('/proc/xen/capabilities') and os.access('/proc/xen/capabilities', os.R_OK): caps = salt.utils.fopen('/proc/xen/capabilities') if 'control_d' not in caps.read(): # Tested on CentOS 5.5 / 2.6.18-194.3.1.el5xen grains['virtual_subtype'] = 'Xen PV DomU' else: # Shouldn't get to this, but just in case grains['virtual_subtype'] = 'Xen Dom0' caps.close() # Tested on Fedora 10 / 2.6.27.30-170.2.82 with xen # Tested on Fedora 15 / 2.6.41.4-1 without running xen elif isdir('/sys/bus/xen'): if 'xen:' in __salt__['cmd.run']('dmesg').lower(): grains['virtual_subtype'] = 'Xen PV DomU' elif os.listdir('/sys/bus/xen/drivers'): # An actual DomU will have several drivers # whereas a paravirt ops kernel will not. grains['virtual_subtype'] = 'Xen PV DomU' # If a Dom0 or DomU was detected, obviously this is xen if 'dom' in grains.get('virtual_subtype', '').lower(): grains['virtual'] = 'xen' if os.path.isfile('/proc/cpuinfo'): if 'QEMU Virtual CPU' in salt.utils.fopen('/proc/cpuinfo', 'r').read(): grains['virtual'] = 'kvm' elif osdata['kernel'] == 'FreeBSD': kenv = salt.utils.which('kenv') if kenv: product = __salt__['cmd.run']('{0} smbios.system.product'.format(kenv)) maker = __salt__['cmd.run']('{0} smbios.system.maker'.format(kenv)) if product.startswith('VMware'): grains['virtual'] = 'VMware' if maker.startswith('Xen'): grains['virtual_subtype'] = '{0} {1}'.format(maker, product) grains['virtual'] = 'xen' if sysctl: model = __salt__['cmd.run']('{0} hw.model'.format(sysctl)) jail = __salt__['cmd.run']('{0} -n security.jail.jailed'.format(sysctl)) if jail == '1': grains['virtual_subtype'] = 'jail' if 'QEMU Virtual CPU' in model: grains['virtual'] = 'kvm' elif osdata['kernel'] == 'SunOS': # Check if it's a "regular" zone. (i.e. Solaris 10/11 zone) zonename = salt.utils.which('zonename') if zonename: zone = __salt__['cmd.run']('{0}'.format(zonename)) if zone != 'global': grains['virtual'] = 'zone' if osdata['os'] == 'SmartOS': grains.update(_smartos_zone_data()) # Check if it's a branded zone (i.e. Solaris 8/9 zone) if isdir('/.SUNWnative'): grains['virtual'] = 'zone' elif osdata['kernel'] == 'NetBSD': if sysctl: if 'QEMU Virtual CPU' in __salt__['cmd.run']( '{0} -n machdep.cpu_brand'.format(sysctl)): grains['virtual'] = 'kvm' elif not 'invalid' in __salt__['cmd.run']( '{0} -n machdep.xen.suspend'.format(sysctl)): grains['virtual'] = 'Xen PV DomU' elif 'VMware' in __salt__['cmd.run']( '{0} -n machdep.dmi.system-vendor'.format(sysctl)): grains['virtual'] = 'VMware' # NetBSD has Xen dom0 support elif __salt__['cmd.run']( '{0} -n machdep.idle-mechanism'.format(sysctl)) == 'xen': if os.path.isfile('/var/run/xenconsoled.pid'): grains['virtual_subtype'] = 'Xen Dom0' return grains
def apply_minion_config(overrides=None, check_dns=True, defaults=None): ''' Returns minion configurations dict. ''' if defaults is None: defaults = DEFAULT_MINION_OPTS opts = defaults.copy() if overrides: opts.update(overrides) if len(opts['sock_dir']) > len(opts['cachedir']) + 10: opts['sock_dir'] = os.path.join(opts['cachedir'], '.salt-unix') if 'append_domain' in opts: opts['id'] = _append_domain(opts) if opts.get('file_client', 'remote') == 'local' and check_dns: check_dns = False if check_dns is True: # Because I import salt.log below I need to re-import salt.utils here import salt.utils try: opts['master_ip'] = salt.utils.dns_check(opts['master'], True) except SaltClientError: if opts['retry_dns']: while True: import salt.log msg = ('Master hostname: {0} not found. Retrying in {1} ' 'seconds').format(opts['master'], opts['retry_dns']) if salt.log.is_console_configured(): log.warn(msg) else: print('WARNING: {0}'.format(msg)) time.sleep(opts['retry_dns']) try: opts['master_ip'] = salt.utils.dns_check( opts['master'], True ) break except SaltClientError: pass else: opts['master_ip'] = '127.0.0.1' else: opts['master_ip'] = '127.0.0.1' opts['master_uri'] = 'tcp://{ip}:{port}'.format(ip=opts['master_ip'], port=opts['master_port']) # Enabling open mode requires that the value be set to True, and # nothing else! opts['open_mode'] = opts['open_mode'] is True # set up the extension_modules location from the cachedir opts['extension_modules'] = ( opts.get('extension_modules') or os.path.join(opts['cachedir'], 'extmods') ) # Prepend root_dir to other paths prepend_root_dirs = [ 'pki_dir', 'cachedir', 'sock_dir', 'extension_modules', 'pidfile', ] # These can be set to syslog, so, not actual paths on the system for config_key in ('log_file', 'key_logfile'): if urlparse.urlparse(opts.get(config_key, '')).scheme == '': prepend_root_dirs.append(config_key) prepend_root_dir(opts, prepend_root_dirs) return opts
def _virtual(osdata): ''' Returns what type of virtual hardware is under the hood, kvm or physical ''' # This is going to be a monster, if you are running a vm you can test this # grain with please submit patches! # Provides: # virtual grains = {'virtual': 'physical'} lspci = salt.utils.which('lspci') dmidecode = salt.utils.which('dmidecode') for command in ('dmidecode', 'lspci'): which = salt.utils.which(command) if which is None: continue ret = __salt__['cmd.run_all'](which) if ret['retcode'] > 0: if salt.log.is_logging_configured(): log.warn( 'Although \'{0}\' was found in path, the current user ' 'cannot execute it. Grains output might not be ' 'accurate.'.format(command) ) continue output = ret['stdout'] if command == 'dmidecode': # Product Name: VirtualBox if 'Vendor: QEMU' in output: # FIXME: Make this detect between kvm or qemu grains['virtual'] = 'kvm' if 'Vendor: Bochs' in output: grains['virtual'] = 'kvm' elif 'VirtualBox' in output: grains['virtual'] = 'VirtualBox' # Product Name: VMware Virtual Platform elif 'VMware' in output: grains['virtual'] = 'VMware' # Manufacturer: Microsoft Corporation # Product Name: Virtual Machine elif 'Manufacturer: Microsoft' in output and 'Virtual Machine' in output: grains['virtual'] = 'VirtualPC' # Manufacturer: Parallels Software International Inc. elif 'Parallels Software' in output: grains['virtual'] = 'Parallels' # Break out of the loop, lspci parsing is not necessary break elif command == 'lspci': # dmidecode not available or the user does not have the necessary # permissions model = output.lower() if 'vmware' in model: grains['virtual'] = 'VMware' # 00:04.0 System peripheral: InnoTek Systemberatung GmbH VirtualBox Guest Service elif 'virtualbox' in model: grains['virtual'] = 'VirtualBox' elif 'qemu' in model: grains['virtual'] = 'kvm' elif 'virtio' in model: grains['virtual'] = 'kvm' # Break out of the loop so the next log message is not issued break else: log.warn( 'Both \'dmidecode\' and \'lspci\' failed to execute, either ' 'because they do not exist on the system of the user running ' 'this instance does not have the necessary permissions to ' 'execute them. Grains output might not be accurate.' ) choices = ('Linux', 'OpenBSD', 'HP-UX') isdir = os.path.isdir if osdata['kernel'] in choices: if isdir('/proc/vz'): if os.path.isfile('/proc/vz/version'): grains['virtual'] = 'openvzhn' else: grains['virtual'] = 'openvzve' elif isdir('/proc/sys/xen') or isdir('/sys/bus/xen') or isdir('/proc/xen'): if os.path.isfile('/proc/xen/xsd_kva'): # Tested on CentOS 5.3 / 2.6.18-194.26.1.el5xen # Tested on CentOS 5.4 / 2.6.18-164.15.1.el5xen grains['virtual_subtype'] = 'Xen Dom0' else: if grains.get('productname', '') == 'HVM domU': # Requires dmidecode! grains['virtual_subtype'] = 'Xen HVM DomU' elif os.path.isfile('/proc/xen/capabilities') and os.access('/proc/xen/capabilities', os.R_OK): caps = open('/proc/xen/capabilities') if 'control_d' not in caps.read(): # Tested on CentOS 5.5 / 2.6.18-194.3.1.el5xen grains['virtual_subtype'] = 'Xen PV DomU' else: # Shouldn't get to this, but just in case grains['virtual_subtype'] = 'Xen Dom0' caps.close() # Tested on Fedora 10 / 2.6.27.30-170.2.82 with xen # Tested on Fedora 15 / 2.6.41.4-1 without running xen elif isdir('/sys/bus/xen'): if 'xen' in __salt__['cmd.run']('dmesg').lower(): grains['virtual_subtype'] = 'Xen PV DomU' elif os.listdir('/sys/bus/xen/drivers'): # An actual DomU will have several drivers # whereas a paravirt ops kernel will not. grains['virtual_subtype'] = 'Xen PV DomU' # If a Dom0 or DomU was detected, obviously this is xen if 'dom' in grains.get('virtual_subtype', '').lower(): grains['virtual'] = 'xen' if os.path.isfile('/proc/cpuinfo'): if 'QEMU Virtual CPU' in open('/proc/cpuinfo', 'r').read(): grains['virtual'] = 'kvm' elif osdata['kernel'] == 'FreeBSD': sysctl = salt.utils.which('sysctl') kenv = salt.utils.which('kenv') if kenv: product = __salt__['cmd.run']('{0} smbios.system.product'.format(kenv)).strip() if product.startswith('VMware'): grains['virtual'] = 'VMware' if sysctl: model = __salt__['cmd.run']('{0} hw.model'.format(sysctl)).strip() jail = __salt__['cmd.run']('{0} -n security.jail.jailed'.format(sysctl)).strip() if jail: grains['virtual_subtype'] = 'jail' if 'QEMU Virtual CPU' in model: grains['virtual'] = 'kvm' elif osdata['kernel'] == 'SunOS': # Check if it's a "regular" zone. (i.e. Solaris 10/11 zone) zonename = salt.utils.which('zonename') if zonename: zone = __salt__['cmd.run']('{0}'.format(zonename)).strip() if zone != "global": grains['virtual'] = 'zone' # Check if it's a branded zone (i.e. Solaris 8/9 zone) if isdir('/.SUNWnative'): grains['virtual'] = 'zone' return grains
def _linux_gpu_data(): ''' num_gpus: int gpus: - vendor: nvidia|amd|ati|... model: string ''' lspci = salt.utils.which('lspci') if not lspci: log.info( 'The `lspci` binary is not available on the system. GPU grains ' 'will not be available.' ) return {} elif __opts__.get('enable_gpu_grains', None) is False: log.info( 'Skipping lspci call because enable_gpu_grains was set to False ' 'in the config. GPU grains will not be available.' ) return {} # dominant gpu vendors to search for (MUST be lowercase for matching below) known_vendors = ['nvidia', 'amd', 'ati', 'intel'] devs = [] try: lspci_out = __salt__['cmd.run']('lspci -vmm') cur_dev = {} error = False # Add a blank element to the lspci_out.splitlines() list, # otherwise the last device is not evaluated as a cur_dev and ignored. lspci_list = lspci_out.splitlines() lspci_list.append('') for line in lspci_list: # check for record-separating empty lines if line == '': if cur_dev.get('Class', '') == 'VGA compatible controller': devs.append(cur_dev) # XXX; may also need to search for "3D controller" cur_dev = {} continue if re.match(r'^\w+:\s+.*', line): key, val = line.split(':', 1) cur_dev[key.strip()] = val.strip() else: error = True log.debug('Unexpected lspci output: \'{0}\''.format(line)) if error: log.warn( 'Error loading grains, unexpected linux_gpu_data output, ' 'check that you have a valid shell configured and ' 'permissions to run lspci command' ) except OSError: pass gpus = [] for gpu in devs: vendor_strings = gpu['Vendor'].lower().split() # default vendor to 'unknown', overwrite if we match a known one vendor = 'unknown' for name in known_vendors: # search for an 'expected' vendor name in the list of strings if name in vendor_strings: vendor = name break gpus.append({'vendor': vendor, 'model': gpu['Device']}) grains = {} grains['num_gpus'] = len(gpus) grains['gpus'] = gpus return grains
def minion_config(path, check_dns=True): ''' Reads in the minion configuration file and sets up special options ''' opts = { 'master': 'salt', 'master_port': '4506', 'master_finger': '', 'user': '******', 'root_dir': '/', 'pki_dir': '/etc/salt/pki/minion', 'id': socket.getfqdn(), 'cachedir': '/var/cache/salt/minion', 'cache_jobs': False, 'conf_file': path, 'sock_dir': '/var/run/salt/minion', 'backup_mode': '', 'renderer': 'yaml_jinja', 'failhard': False, 'autoload_dynamic_modules': True, 'environment': None, 'state_top': 'top.sls', 'startup_states': '', 'sls_list': [], 'top_file': '', 'file_client': 'remote', 'file_roots': { 'base': ['/srv/salt'], }, 'pillar_roots': { 'base': ['/srv/pillar'], }, 'hash_type': 'md5', 'external_nodes': '', 'disable_modules': [], 'disable_returners': [], 'module_dirs': [], 'returner_dirs': [], 'states_dirs': [], 'render_dirs': [], 'providers': {}, 'clean_dynamic_modules': True, 'open_mode': False, 'multiprocessing': True, 'sub_timeout': 0, 'ipc_mode': 'ipc', 'tcp_pub_port': 4510, 'tcp_pull_port': 4511, 'log_file': '/var/log/salt/minion', 'log_level': None, 'log_level_logfile': None, 'log_datefmt': __dflt_log_datefmt, 'log_fmt_console': __dflt_log_fmt_console, 'log_fmt_logfile': __dflt_log_fmt_logfile, 'log_granular_levels': {}, 'test': False, 'cython_enable': False, 'state_verbose': True, 'state_output': 'full', 'acceptance_wait_time': 10, 'dns_check': True, 'verify_env': True, 'grains': {}, 'permissive_pki_access': False, 'default_include': 'minion.d/*.conf', 'update_url': False, 'update_restart_services': [], 'retry_dns': 30, 'recon_max': 5000, 'pidfile': '/var/run/salt-minion.pid', } if len(opts['sock_dir']) > len(opts['cachedir']) + 10: opts['sock_dir'] = os.path.join(opts['cachedir'], '.salt-unix') load_config(opts, path, 'SALT_MINION_CONFIG') default_include = opts.get('default_include', []) include = opts.get('include', []) opts = include_config(default_include, opts, path, verbose=False) opts = include_config(include, opts, path, verbose=True) if 'append_domain' in opts: opts['id'] = _append_domain(opts) if opts.get('file_client', 'remote') == 'local' and check_dns: check_dns = False if check_dns is True: # Because I import salt.log below I need to re-import salt.utils here import salt.utils try: opts['master_ip'] = salt.utils.dns_check(opts['master'], True) except SaltClientError: if opts['retry_dns']: while True: import salt.log msg = ('Master hostname: {0} not found. Retrying in {1} ' 'seconds').format(opts['master'], opts['retry_dns']) if salt.log.is_console_configured(): log.warn(msg) else: print('WARNING: {0}'.format(msg)) time.sleep(opts['retry_dns']) try: opts['master_ip'] = salt.utils.dns_check( opts['master'], True) break except SaltClientError: pass else: opts['master_ip'] = '127.0.0.1' else: opts['master_ip'] = '127.0.0.1' opts['master_uri'] = 'tcp://{ip}:{port}'.format(ip=opts['master_ip'], port=opts['master_port']) # Enabling open mode requires that the value be set to True, and # nothing else! opts['open_mode'] = opts['open_mode'] is True # set up the extension_modules location from the cachedir opts['extension_modules'] = (opts.get('extension_modules') or os.path.join(opts['cachedir'], 'extmods')) # Prepend root_dir to other paths prepend_root_dirs = [ 'pki_dir', 'cachedir', 'sock_dir', 'extension_modules', 'pidfile', ] # These can be set to syslog, so, not actual paths on the system for config_key in ('log_file', 'key_logfile'): if urlparse.urlparse(opts.get(config_key, '')).scheme == '': prepend_root_dirs.append(config_key) prepend_root_dir(opts, prepend_root_dirs) return opts
def _virtual(osdata): ''' Returns what type of virtual hardware is under the hood, kvm or physical ''' # This is going to be a monster, if you are running a vm you can test this # grain with please submit patches! # Provides: # virtual # virtual_subtype grains = {'virtual': 'physical'} for command in ('dmidecode', 'lspci'): cmd = salt.utils.which(command) if not cmd: continue ret = __salt__['cmd.run_all'](cmd) if ret['retcode'] > 0: if salt.log.is_logging_configured(): log.warn( 'Although \'{0}\' was found in path, the current user ' 'cannot execute it. Grains output might not be ' 'accurate.'.format(command)) continue output = ret['stdout'] if command == 'dmidecode': # Product Name: VirtualBox if 'Vendor: QEMU' in output: # FIXME: Make this detect between kvm or qemu grains['virtual'] = 'kvm' if 'Vendor: Bochs' in output: grains['virtual'] = 'kvm' elif 'VirtualBox' in output: grains['virtual'] = 'VirtualBox' # Product Name: VMware Virtual Platform elif 'VMware' in output: grains['virtual'] = 'VMware' # Manufacturer: Microsoft Corporation # Product Name: Virtual Machine elif 'Manufacturer: Microsoft' in output and 'Virtual Machine' in output: grains['virtual'] = 'VirtualPC' # Manufacturer: Parallels Software International Inc. elif 'Parallels Software' in output: grains['virtual'] = 'Parallels' # Break out of the loop, lspci parsing is not necessary break elif command == 'lspci': # dmidecode not available or the user does not have the necessary # permissions model = output.lower() if 'vmware' in model: grains['virtual'] = 'VMware' # 00:04.0 System peripheral: InnoTek Systemberatung GmbH VirtualBox Guest Service elif 'virtualbox' in model: grains['virtual'] = 'VirtualBox' elif 'qemu' in model: grains['virtual'] = 'kvm' elif 'virtio' in model: grains['virtual'] = 'kvm' # Break out of the loop so the next log message is not issued break else: log.warn('Both \'dmidecode\' and \'lspci\' failed to execute, either ' 'because they do not exist on the system of the user running ' 'this instance does not have the necessary permissions to ' 'execute them. Grains output might not be accurate.') choices = ('Linux', 'OpenBSD', 'HP-UX') isdir = os.path.isdir if osdata['kernel'] in choices: if isdir('/proc/vz'): if os.path.isfile('/proc/vz/version'): grains['virtual'] = 'openvzhn' else: grains['virtual'] = 'openvzve' elif isdir('/proc/sys/xen') or isdir('/sys/bus/xen') or isdir( '/proc/xen'): if os.path.isfile('/proc/xen/xsd_kva'): # Tested on CentOS 5.3 / 2.6.18-194.26.1.el5xen # Tested on CentOS 5.4 / 2.6.18-164.15.1.el5xen grains['virtual_subtype'] = 'Xen Dom0' else: if grains.get('productname', '') == 'HVM domU': # Requires dmidecode! grains['virtual_subtype'] = 'Xen HVM DomU' elif os.path.isfile('/proc/xen/capabilities') and os.access( '/proc/xen/capabilities', os.R_OK): caps = salt.utils.fopen('/proc/xen/capabilities') if 'control_d' not in caps.read(): # Tested on CentOS 5.5 / 2.6.18-194.3.1.el5xen grains['virtual_subtype'] = 'Xen PV DomU' else: # Shouldn't get to this, but just in case grains['virtual_subtype'] = 'Xen Dom0' caps.close() # Tested on Fedora 10 / 2.6.27.30-170.2.82 with xen # Tested on Fedora 15 / 2.6.41.4-1 without running xen elif isdir('/sys/bus/xen'): if 'xen' in __salt__['cmd.run']('dmesg').lower(): grains['virtual_subtype'] = 'Xen PV DomU' elif os.listdir('/sys/bus/xen/drivers'): # An actual DomU will have several drivers # whereas a paravirt ops kernel will not. grains['virtual_subtype'] = 'Xen PV DomU' # If a Dom0 or DomU was detected, obviously this is xen if 'dom' in grains.get('virtual_subtype', '').lower(): grains['virtual'] = 'xen' if os.path.isfile('/proc/cpuinfo'): if 'QEMU Virtual CPU' in salt.utils.fopen('/proc/cpuinfo', 'r').read(): grains['virtual'] = 'kvm' elif osdata['kernel'] == 'FreeBSD': sysctl = salt.utils.which('sysctl') kenv = salt.utils.which('kenv') if kenv: product = __salt__['cmd.run']( '{0} smbios.system.product'.format(kenv)) if product.startswith('VMware'): grains['virtual'] = 'VMware' if sysctl: model = __salt__['cmd.run']('{0} hw.model'.format(sysctl)) jail = __salt__['cmd.run']( '{0} -n security.jail.jailed'.format(sysctl)) if jail == '1': grains['virtual_subtype'] = 'jail' if 'QEMU Virtual CPU' in model: grains['virtual'] = 'kvm' elif osdata['kernel'] == 'SunOS': # Check if it's a "regular" zone. (i.e. Solaris 10/11 zone) zonename = salt.utils.which('zonename') if zonename: zone = __salt__['cmd.run']('{0}'.format(zonename)) if zone != "global": grains['virtual'] = 'zone' # Check if it's a branded zone (i.e. Solaris 8/9 zone) if isdir('/.SUNWnative'): grains['virtual'] = 'zone' return grains
def _linux_gpu_data(): """ num_gpus: int gpus: - vendor: nvidia|amd|ati|... model: string """ lspci = salt.utils.which("lspci") if not lspci: log.info("The `lspci` binary is not available on the system. GPU grains " "will not be available.") return {} elif __opts__.get("enable_gpu_grains", None) is False: log.info( "Skipping lspci call because enable_gpu_grains was set to False " "in the config. GPU grains will not be available." ) return {} # dominant gpu vendors to search for (MUST be lowercase for matching below) known_vendors = ["nvidia", "amd", "ati", "intel"] devs = [] try: lspci_out = __salt__["cmd.run"]("lspci -vmm") cur_dev = {} error = False # Add a blank element to the lspci_out.splitlines() list, # otherwise the last device is not evaluated as a cur_dev and ignored. lspci_list = lspci_out.splitlines() lspci_list.append("") for line in lspci_list: # check for record-separating empty lines if line == "": if cur_dev.get("Class", "") == "VGA compatible controller": devs.append(cur_dev) # XXX; may also need to search for "3D controller" cur_dev = {} continue if re.match(r"^\w+:\s+.*", line): key, val = line.split(":", 1) cur_dev[key.strip()] = val.strip() else: error = True log.debug("Unexpected lspci output: '{0}'".format(line)) if error: log.warn( "Error loading grains, unexpected linux_gpu_data output, " "check that you have a valid shell configured and " "permissions to run lspci command" ) except OSError: pass gpus = [] for gpu in devs: vendor_strings = gpu["Vendor"].lower().split() # default vendor to 'unknown', overwrite if we match a known one vendor = "unknown" for name in known_vendors: # search for an 'expected' vendor name in the list of strings if name in vendor_strings: vendor = name break gpus.append({"vendor": vendor, "model": gpu["Device"]}) grains = {} grains["num_gpus"] = len(gpus) grains["gpus"] = gpus return grains
def minion_config(path, check_dns=True): ''' Reads in the minion configuration file and sets up special options ''' opts = {'master': 'salt', 'master_port': '4506', 'master_finger': '', 'user': '******', 'root_dir': '/', 'pki_dir': '/etc/salt/pki/minion', 'id': socket.getfqdn(), 'cachedir': '/var/cache/salt/minion', 'cache_jobs': False, 'conf_file': path, 'sock_dir': '/var/run/salt/minion', 'backup_mode': '', 'renderer': 'yaml_jinja', 'failhard': False, 'autoload_dynamic_modules': True, 'environment': None, 'state_top': 'top.sls', 'startup_states': '', 'sls_list': [], 'top_file': '', 'file_client': 'remote', 'file_roots': { 'base': ['/srv/salt'], }, 'pillar_roots': { 'base': ['/srv/pillar'], }, 'hash_type': 'md5', 'external_nodes': '', 'disable_modules': [], 'disable_returners': [], 'module_dirs': [], 'returner_dirs': [], 'states_dirs': [], 'render_dirs': [], 'providers': {}, 'clean_dynamic_modules': True, 'open_mode': False, 'multiprocessing': True, 'sub_timeout': 0, 'ipc_mode': 'ipc', 'tcp_pub_port': 4510, 'tcp_pull_port': 4511, 'log_file': '/var/log/salt/minion', 'log_level': None, 'log_level_logfile': None, 'log_datefmt': __dflt_log_datefmt, 'log_fmt_console': __dflt_log_fmt_console, 'log_fmt_logfile': __dflt_log_fmt_logfile, 'log_granular_levels': {}, 'test': False, 'cython_enable': False, 'state_verbose': True, 'state_output': 'full', 'acceptance_wait_time': 10, 'dns_check': True, 'verify_env': True, 'grains': {}, 'permissive_pki_access': False, 'default_include': 'minion.d/*.conf', 'update_url': False, 'update_restart_services': [], 'retry_dns': 30, 'recon_max': 5000, } if len(opts['sock_dir']) > len(opts['cachedir']) + 10: opts['sock_dir'] = os.path.join(opts['cachedir'], '.salt-unix') load_config(opts, path, 'SALT_MINION_CONFIG') default_include = opts.get('default_include', []) include = opts.get('include', []) opts = include_config(default_include, opts, path, verbose=False) opts = include_config(include, opts, path, verbose=True) if 'append_domain' in opts: opts['id'] = _append_domain(opts) if opts.get('file_client', 'remote') == 'local' and check_dns: check_dns = False if check_dns is True: # Because I import salt.log below I need to re-import salt.utils here import salt.utils try: opts['master_ip'] = salt.utils.dns_check(opts['master'], True) except SaltClientError: if opts['retry_dns']: while True: import salt.log msg = ('Master hostname: {0} not found. Retrying in {1} ' 'seconds').format(opts['master'], opts['retry_dns']) if salt.log.is_console_configured(): log.warn(msg) else: print('WARNING: {0}'.format(msg)) time.sleep(opts['retry_dns']) try: opts['master_ip'] = salt.utils.dns_check( opts['master'], True ) break except SaltClientError: pass else: opts['master_ip'] = '127.0.0.1' else: opts['master_ip'] = '127.0.0.1' opts['master_uri'] = 'tcp://{ip}:{port}'.format(ip=opts['master_ip'], port=opts['master_port']) # Enabling open mode requires that the value be set to True, and # nothing else! opts['open_mode'] = opts['open_mode'] is True # set up the extension_modules location from the cachedir opts['extension_modules'] = ( opts.get('extension_modules') or os.path.join(opts['cachedir'], 'extmods') ) # Prepend root_dir to other paths prepend_root_dirs = [ 'pki_dir', 'cachedir', 'sock_dir', 'extension_modules' ] # These can be set to syslog, so, not actual paths on the system for config_key in ('log_file', 'key_logfile'): if urlparse.urlparse(opts.get(config_key, '')).scheme == '': prepend_root_dirs.append(config_key) prepend_root_dir(opts, prepend_root_dirs) return opts
class Minion(object): ''' Create a minion server ''' def __init__(self): self.cli = self.__parse_cli() # command line overrides config if self.cli['user']: self.opts['user'] = self.cli['user'] def __parse_cli(self): ''' Parse the cli input ''' import salt.log parser = optparse.OptionParser(version="%%prog %s" % __version__) parser.add_option('-d', '--daemon', dest='daemon', default=False, action='store_true', help='Run the minion as a daemon') parser.add_option('-c', '--config', dest='config', default='/etc/salt/minion', help='Pass in an alternative configuration file') parser.add_option('-u', '--user', dest='user', help='Specify user to run minion') parser.add_option('--pid-file', dest='pidfile', default='/var/run/salt-minion.pid', help=('Specify the location of the pidfile. Default' ' %default')) parser.add_option( '-l', '--log-level', dest='log_level', choices=list(salt.log.LOG_LEVELS), help='Console log level. One of %s. For the logfile settings ' 'see the config file. Default: \'warning\'.' % ', '.join([repr(l) for l in salt.log.SORTED_LEVEL_NAMES])) options, args = parser.parse_args() self.opts = salt.config.minion_config(options.config) if not options.log_level: options.log_level = self.opts['log_level'] salt.log.setup_console_logger(options.log_level, log_format=self.opts['log_fmt_console'], date_format=self.opts['log_datefmt']) cli = { 'daemon': options.daemon, 'config': options.config, 'user': options.user, 'pidfile': options.pidfile } return cli def start(self): ''' Execute this method to start up a minion. ''' try: verify_env([ self.opts['pki_dir'], self.opts['cachedir'], self.opts['sock_dir'], self.opts['extension_modules'], os.path.dirname(self.opts['log_file']), ], self.opts['user'], permissive=self.opts['permissive_pki_access']) except OSError, err: sys.exit(err.errno) import salt.log salt.log.setup_logfile_logger(self.opts['log_file'], self.opts['log_level_logfile'] or self.opts['log_level'], log_format=self.opts['log_fmt_logfile'], date_format=self.opts['log_datefmt']) for name, level in self.opts['log_granular_levels'].items(): salt.log.set_logger_level(name, level) import logging # Late import so logging works correctly import salt.minion log = logging.getLogger(__name__) if self.cli['daemon']: # Late import so logging works correctly import salt.utils # If the minion key has not been accepted, then Salt enters a loop # waiting for it, if we daemonize later then the minion could halt # the boot process waiting for a key to be accepted on the master. # This is the latest safe place to daemonize salt.utils.daemonize() try: minion = salt.minion.Minion(self.opts) set_pidfile(self.cli['pidfile']) if check_user(self.opts['user'], log): minion.tune_in() except KeyboardInterrupt: log.warn('Stopping the Salt Minion') raise SystemExit('\nExiting on Ctrl-c')
def _virtual(osdata): """ Returns what type of virtual hardware is under the hood, kvm or physical """ # This is going to be a monster, if you are running a vm you can test this # grain with please submit patches! # Provides: # virtual # virtual_subtype grains = {"virtual": "physical"} for command in ("dmidecode", "lspci", "dmesg"): args = [] if osdata["kernel"] == "Darwin": command = "system_profiler" args = ["SPDisplaysDataType"] cmd = salt.utils.which(command) if not cmd: continue cmd = "%s %s" % (command, " ".join(args)) ret = __salt__["cmd.run_all"](cmd) if ret["retcode"] > 0: if salt.log.is_logging_configured(): if salt.utils.is_windows(): continue log.warn( "Although '{0}' was found in path, the current user " "cannot execute it. Grains output might not be " "accurate.".format(command) ) continue output = ret["stdout"] if command == "system_profiler": macoutput = output.lower() if "0x1ab8" in macoutput: grains["virtual"] = "Parallels" if "parallels" in macoutput: grains["virtual"] = "Parallels" if "vmware" in macoutput: grains["virtual"] = "VMware" if "0x15ad" in macoutput: grains["virtual"] = "VMware" if "virtualbox" in macoutput: grains["virtual"] = "VirtualBox" # Break out of the loop so the next log message is not issued break elif command == "dmidecode" or command == "dmesg": # Product Name: VirtualBox if "Vendor: QEMU" in output: # FIXME: Make this detect between kvm or qemu grains["virtual"] = "kvm" if "Vendor: Bochs" in output: grains["virtual"] = "kvm" # Product Name: (oVirt) www.ovirt.org # Red Hat Community virtualization Project based on kvm elif "Manufacturer: oVirt" in output: grains["virtual"] = "kvm" elif "VirtualBox" in output: grains["virtual"] = "VirtualBox" # Product Name: VMware Virtual Platform elif "VMware" in output: grains["virtual"] = "VMware" # Manufacturer: Microsoft Corporation # Product Name: Virtual Machine elif ": Microsoft" in output and "Virtual Machine" in output: grains["virtual"] = "VirtualPC" # Manufacturer: Parallels Software International Inc. elif "Parallels Software" in output: grains["virtual"] = "Parallels" # Break out of the loop, lspci parsing is not necessary break elif command == "lspci": # dmidecode not available or the user does not have the necessary # permissions model = output.lower() if "vmware" in model: grains["virtual"] = "VMware" # 00:04.0 System peripheral: InnoTek Systemberatung GmbH VirtualBox Guest Service elif "virtualbox" in model: grains["virtual"] = "VirtualBox" elif "qemu" in model: grains["virtual"] = "kvm" elif "virtio" in model: grains["virtual"] = "kvm" # Break out of the loop so the next log message is not issued break else: log.warn( "The tools 'dmidecode', 'lspci' and 'dmesg' failed to execute " "because they do not exist on the system of the user running " "this instance or the user does not have the necessary permissions " "to execute them. Grains output might not be accurate." ) choices = ("Linux", "OpenBSD", "HP-UX") isdir = os.path.isdir sysctl = salt.utils.which("sysctl") if osdata["kernel"] in choices: if os.path.isfile("/proc/1/cgroup"): if ":/lxc/" in salt.utils.fopen("/proc/1/cgroup", "r").read(): grains["virtual_subtype"] = "LXC" if isdir("/proc/vz"): if os.path.isfile("/proc/vz/version"): grains["virtual"] = "openvzhn" else: grains["virtual"] = "openvzve" elif isdir("/proc/sys/xen") or isdir("/sys/bus/xen") or isdir("/proc/xen"): if os.path.isfile("/proc/xen/xsd_kva"): # Tested on CentOS 5.3 / 2.6.18-194.26.1.el5xen # Tested on CentOS 5.4 / 2.6.18-164.15.1.el5xen grains["virtual_subtype"] = "Xen Dom0" else: if grains.get("productname", "") == "HVM domU": # Requires dmidecode! grains["virtual_subtype"] = "Xen HVM DomU" elif os.path.isfile("/proc/xen/capabilities") and os.access("/proc/xen/capabilities", os.R_OK): caps = salt.utils.fopen("/proc/xen/capabilities") if "control_d" not in caps.read(): # Tested on CentOS 5.5 / 2.6.18-194.3.1.el5xen grains["virtual_subtype"] = "Xen PV DomU" else: # Shouldn't get to this, but just in case grains["virtual_subtype"] = "Xen Dom0" caps.close() # Tested on Fedora 10 / 2.6.27.30-170.2.82 with xen # Tested on Fedora 15 / 2.6.41.4-1 without running xen elif isdir("/sys/bus/xen"): if "xen:" in __salt__["cmd.run"]("dmesg").lower(): grains["virtual_subtype"] = "Xen PV DomU" elif os.listdir("/sys/bus/xen/drivers"): # An actual DomU will have several drivers # whereas a paravirt ops kernel will not. grains["virtual_subtype"] = "Xen PV DomU" # If a Dom0 or DomU was detected, obviously this is xen if "dom" in grains.get("virtual_subtype", "").lower(): grains["virtual"] = "xen" if os.path.isfile("/proc/cpuinfo"): if "QEMU Virtual CPU" in salt.utils.fopen("/proc/cpuinfo", "r").read(): grains["virtual"] = "kvm" elif osdata["kernel"] == "FreeBSD": kenv = salt.utils.which("kenv") if kenv: product = __salt__["cmd.run"]("{0} smbios.system.product".format(kenv)) maker = __salt__["cmd.run"]("{0} smbios.system.maker".format(kenv)) if product.startswith("VMware"): grains["virtual"] = "VMware" if maker.startswith("Xen"): grains["virtual_subtype"] = "{0} {1}".format(maker, product) grains["virtual"] = "xen" if sysctl: model = __salt__["cmd.run"]("{0} hw.model".format(sysctl)) jail = __salt__["cmd.run"]("{0} -n security.jail.jailed".format(sysctl)) if jail == "1": grains["virtual_subtype"] = "jail" if "QEMU Virtual CPU" in model: grains["virtual"] = "kvm" elif osdata["kernel"] == "SunOS": # Check if it's a "regular" zone. (i.e. Solaris 10/11 zone) zonename = salt.utils.which("zonename") if zonename: zone = __salt__["cmd.run"]("{0}".format(zonename)) if zone != "global": grains["virtual"] = "zone" if osdata["os"] == "SmartOS": grains.update(_smartos_zone_data()) # Check if it's a branded zone (i.e. Solaris 8/9 zone) if isdir("/.SUNWnative"): grains["virtual"] = "zone" elif osdata["kernel"] == "NetBSD": if sysctl: if "QEMU Virtual CPU" in __salt__["cmd.run"]("{0} -n machdep.cpu_brand".format(sysctl)): grains["virtual"] = "kvm" elif not "invalid" in __salt__["cmd.run"]("{0} -n machdep.xen.suspend".format(sysctl)): grains["virtual"] = "Xen PV DomU" elif "VMware" in __salt__["cmd.run"]("{0} -n machdep.dmi.system-vendor".format(sysctl)): grains["virtual"] = "VMware" # NetBSD has Xen dom0 support elif __salt__["cmd.run"]("{0} -n machdep.idle-mechanism".format(sysctl)) == "xen": if os.path.isfile("/var/run/xenconsoled.pid"): grains["virtual_subtype"] = "Xen Dom0" return grains
class Syndic(object): ''' Create a syndic server ''' def __init__(self): self.cli = self.__parse_cli() # command line overrides config if self.cli['user']: self.opts['user'] = self.cli['user'] def __prep_opts(self, cli): ''' Generate the opts used by the syndic ''' opts = salt.config.master_config(cli['master_config']) opts['_minion_conf_file'] = opts['conf_file'] opts.update(salt.config.minion_config(cli['minion_config'])) if 'syndic_master' in opts: # Some of the opts need to be changed to match the needed opts # in the minion class. opts['master'] = opts['syndic_master'] opts['master_ip'] = salt.utils.dns_check(opts['master']) opts['master_uri'] = ('tcp://' + opts['master_ip'] + ':' + str(opts['master_port'])) opts['_master_conf_file'] = opts['conf_file'] opts.pop('conf_file') return opts err = ('The syndic_master needs to be configured in the salt master ' 'config, EXITING!\n') sys.stderr.write(err) sys.exit(2) def __parse_cli(self): ''' Parse the cli for options passed to a syndic daemon ''' import salt.log parser = optparse.OptionParser(version="%%prog %s" % __version__) parser.add_option('-d', '--daemon', dest='daemon', default=False, action='store_true', help='Run the syndic as a daemon') parser.add_option( '--master-config', dest='master_config', default='/etc/salt/master', help='Pass in an alternative master configuration file') parser.add_option( '--minion-config', dest='minion_config', default='/etc/salt/minion', help='Pass in an alternative minion configuration file') parser.add_option('-u', '--user', dest='user', help='Specify user to run syndic') parser.add_option('--pid-file', dest='pidfile', default='/var/run/salt-syndic.pid', help=('Specify the location of the pidfile. Default' ' %default')) parser.add_option( '-l', '--log-level', dest='log_level', choices=list(salt.log.LOG_LEVELS), help='Console log level. One of %s. For the logfile settings ' 'see the config file. Default: \'warning\'.' % ', '.join([repr(l) for l in salt.log.LOG_LEVELS])) options, args = parser.parse_args() cli = { 'daemon': options.daemon, 'minion_config': options.minion_config, 'master_config': options.master_config, 'pidfile': options.pidfile, 'user': options.user } self.opts = self.__prep_opts(cli) if not options.log_level: options.log_level = self.opts['log_level'] salt.log.setup_console_logger(options.log_level, log_format=self.opts['log_fmt_console'], date_format=self.opts['log_datefmt']) return cli def start(self): ''' Execute this method to start up a syndic. ''' try: verify_env([ self.opts['pki_dir'], self.opts['cachedir'], os.path.dirname(self.opts['log_file']), ], self.opts['user'], permissive=self.opts['permissive_pki_access']) except OSError, err: sys.exit(err.errno) import salt.log salt.log.setup_logfile_logger(self.opts['log_file'], self.opts['log_level']) for name, level in self.opts['log_granular_levels'].items(): salt.log.set_logger_level(name, level) import logging # Late import so logging works correctly import salt.minion log = logging.getLogger(__name__) if self.cli['daemon']: # Late import so logging works correctly import salt.utils salt.utils.daemonize() set_pidfile(self.cli['pidfile']) if check_user(self.opts['user'], log): try: syndic = salt.minion.Syndic(self.opts) syndic.tune_in() except KeyboardInterrupt: log.warn('Stopping the Salt Syndic Minion') raise SystemExit('\nExiting on Ctrl-c')
def _virtual(osdata): ''' Returns what type of virtual hardware is under the hood, kvm or physical ''' # This is going to be a monster, if you are running a vm you can test this # grain with please submit patches! # Provides: # virtual # virtual_subtype grains = {'virtual': 'physical'} for command in ('dmidecode', 'lspci', 'dmesg'): args = [] if osdata['kernel'] == 'Darwin': command = 'system_profiler' args = ['SPDisplaysDataType'] cmd = salt.utils.which(command) if not cmd: continue cmd = '%s %s' % (command, ' '.join(args)) ret = __salt__['cmd.run_all'](cmd) if ret['retcode'] > 0: if salt.log.is_logging_configured(): if salt.utils.is_windows(): continue log.warn( 'Although \'{0}\' was found in path, the current user ' 'cannot execute it. Grains output might not be ' 'accurate.'.format(command)) continue output = ret['stdout'] if command == "system_profiler": macoutput = output.lower() if '0x1ab8' in macoutput: grains['virtual'] = 'Parallels' if 'parallels' in macoutput: grains['virtual'] = 'Parallels' if 'vmware' in macoutput: grains['virtual'] = 'VMware' if '0x15ad' in macoutput: grains['virtual'] = 'VMware' if 'virtualbox' in macoutput: grains['virtual'] = 'VirtualBox' # Break out of the loop so the next log message is not issued break elif command == 'dmidecode' or command == 'dmesg': # Product Name: VirtualBox if 'Vendor: QEMU' in output: # FIXME: Make this detect between kvm or qemu grains['virtual'] = 'kvm' if 'Vendor: Bochs' in output: grains['virtual'] = 'kvm' # Product Name: (oVirt) www.ovirt.org # Red Hat Community virtualization Project based on kvm elif 'Manufacturer: oVirt' in output: grains['virtual'] = 'kvm' elif 'VirtualBox' in output: grains['virtual'] = 'VirtualBox' # Product Name: VMware Virtual Platform elif 'VMware' in output: grains['virtual'] = 'VMware' # Manufacturer: Microsoft Corporation # Product Name: Virtual Machine elif ': Microsoft' in output and 'Virtual Machine' in output: grains['virtual'] = 'VirtualPC' # Manufacturer: Parallels Software International Inc. elif 'Parallels Software' in output: grains['virtual'] = 'Parallels' # Break out of the loop, lspci parsing is not necessary break elif command == 'lspci': # dmidecode not available or the user does not have the necessary # permissions model = output.lower() if 'vmware' in model: grains['virtual'] = 'VMware' # 00:04.0 System peripheral: InnoTek Systemberatung GmbH VirtualBox Guest Service elif 'virtualbox' in model: grains['virtual'] = 'VirtualBox' elif 'qemu' in model: grains['virtual'] = 'kvm' elif 'virtio' in model: grains['virtual'] = 'kvm' # Break out of the loop so the next log message is not issued break else: log.warn( 'The tools \'dmidecode\', \'lspci\' and \'dmesg\' failed to execute ' 'because they do not exist on the system of the user running ' 'this instance or the user does not have the necessary permissions ' 'to execute them. Grains output might not be accurate.') choices = ('Linux', 'OpenBSD', 'HP-UX') isdir = os.path.isdir sysctl = salt.utils.which('sysctl') if osdata['kernel'] in choices: if os.path.isfile('/proc/1/cgroup'): try: if ':/lxc/' in salt.utils.fopen('/proc/1/cgroup', 'r').read(): grains['virtual_subtype'] = 'LXC' except IOError: pass if isdir('/proc/vz'): if os.path.isfile('/proc/vz/version'): grains['virtual'] = 'openvzhn' elif os.path.isfile('/proc/vz/veinfo'): grains['virtual'] = 'openvzve' elif isdir('/proc/sys/xen') or isdir('/sys/bus/xen') or isdir( '/proc/xen'): if os.path.isfile('/proc/xen/xsd_kva'): # Tested on CentOS 5.3 / 2.6.18-194.26.1.el5xen # Tested on CentOS 5.4 / 2.6.18-164.15.1.el5xen grains['virtual_subtype'] = 'Xen Dom0' else: if grains.get('productname', '') == 'HVM domU': # Requires dmidecode! grains['virtual_subtype'] = 'Xen HVM DomU' elif os.path.isfile('/proc/xen/capabilities') and os.access( '/proc/xen/capabilities', os.R_OK): caps = salt.utils.fopen('/proc/xen/capabilities') if 'control_d' not in caps.read(): # Tested on CentOS 5.5 / 2.6.18-194.3.1.el5xen grains['virtual_subtype'] = 'Xen PV DomU' else: # Shouldn't get to this, but just in case grains['virtual_subtype'] = 'Xen Dom0' caps.close() # Tested on Fedora 10 / 2.6.27.30-170.2.82 with xen # Tested on Fedora 15 / 2.6.41.4-1 without running xen elif isdir('/sys/bus/xen'): if 'xen:' in __salt__['cmd.run']('dmesg').lower(): grains['virtual_subtype'] = 'Xen PV DomU' elif os.listdir('/sys/bus/xen/drivers'): # An actual DomU will have several drivers # whereas a paravirt ops kernel will not. grains['virtual_subtype'] = 'Xen PV DomU' # If a Dom0 or DomU was detected, obviously this is xen if 'dom' in grains.get('virtual_subtype', '').lower(): grains['virtual'] = 'xen' if os.path.isfile('/proc/cpuinfo'): if 'QEMU Virtual CPU' in salt.utils.fopen('/proc/cpuinfo', 'r').read(): grains['virtual'] = 'kvm' elif osdata['kernel'] == 'FreeBSD': kenv = salt.utils.which('kenv') if kenv: product = __salt__['cmd.run']( '{0} smbios.system.product'.format(kenv)) maker = __salt__['cmd.run']('{0} smbios.system.maker'.format(kenv)) if product.startswith('VMware'): grains['virtual'] = 'VMware' if maker.startswith('Xen'): grains['virtual_subtype'] = '{0} {1}'.format(maker, product) grains['virtual'] = 'xen' if sysctl: model = __salt__['cmd.run']('{0} hw.model'.format(sysctl)) jail = __salt__['cmd.run']( '{0} -n security.jail.jailed'.format(sysctl)) if jail == '1': grains['virtual_subtype'] = 'jail' if 'QEMU Virtual CPU' in model: grains['virtual'] = 'kvm' elif osdata['kernel'] == 'SunOS': # Check if it's a "regular" zone. (i.e. Solaris 10/11 zone) zonename = salt.utils.which('zonename') if zonename: zone = __salt__['cmd.run']('{0}'.format(zonename)) if zone != 'global': grains['virtual'] = 'zone' if osdata['os'] == 'SmartOS': grains.update(_smartos_zone_data()) # Check if it's a branded zone (i.e. Solaris 8/9 zone) if isdir('/.SUNWnative'): grains['virtual'] = 'zone' elif osdata['kernel'] == 'NetBSD': if sysctl: if 'QEMU Virtual CPU' in __salt__['cmd.run']( '{0} -n machdep.cpu_brand'.format(sysctl)): grains['virtual'] = 'kvm' elif not 'invalid' in __salt__['cmd.run']( '{0} -n machdep.xen.suspend'.format(sysctl)): grains['virtual'] = 'Xen PV DomU' elif 'VMware' in __salt__['cmd.run']( '{0} -n machdep.dmi.system-vendor'.format(sysctl)): grains['virtual'] = 'VMware' # NetBSD has Xen dom0 support elif __salt__['cmd.run']( '{0} -n machdep.idle-mechanism'.format(sysctl)) == 'xen': if os.path.isfile('/var/run/xenconsoled.pid'): grains['virtual_subtype'] = 'Xen Dom0' return grains
def load_config(path, env_var, default_path=None): ''' Returns configuration dict from parsing either the file described by ``path`` or the environment variable described by ``env_var`` as YAML. ''' if path is None: # When the passed path is None, we just want the configuration # defaults, not actually loading the whole configuration. return {} if default_path is None: # This is most likely not being used from salt, ie, could be salt-cloud # or salt-api which have not yet migrated to the new default_path # argument. Let's issue a warning message that the environ vars won't # work. import inspect previous_frame = inspect.getframeinfo(inspect.currentframe().f_back) log.warning( 'The function \'{0}()\' defined in {1!r} is not yet using the ' 'new \'default_path\' argument to `salt.config.load_config()`. ' 'As such, the {2!r} environment variable will be ignored'.format( previous_frame.function, previous_frame.filename, env_var)) # In this case, maintain old behaviour default_path = DEFAULT_MASTER_OPTS['conf_file'] # Default to the environment variable path, if it exists env_path = os.environ.get(env_var, path) if not env_path or not os.path.isfile(env_path): env_path = path # If non-default path from `-c`, use that over the env variable if path != default_path: env_path = path path = env_path # If the configuration file is missing, attempt to copy the template, # after removing the first header line. if not os.path.isfile(path): template = '{0}.template'.format(path) if os.path.isfile(template): import salt.utils # TODO: Need to re-import, need to find out why log.debug('Writing {0} based on {1}'.format(path, template)) with salt.utils.fopen(path, 'w') as out: with salt.utils.fopen(template, 'r') as ifile: ifile.readline() # skip first line out.write(ifile.read()) if os.path.isfile(path): try: opts = _read_conf_file(path) opts['conf_file'] = path return opts except Exception as err: import salt.log msg = 'Error parsing configuration file: {0} - {1}' if salt.log.is_console_configured(): log.warn(msg.format(path, err)) else: print(msg.format(path, err)) else: log.debug('Missing configuration file: {0}'.format(path)) return {}
def load_config(path, env_var, default_path=None): ''' Returns configuration dict from parsing either the file described by ``path`` or the environment variable described by ``env_var`` as YAML. ''' if path is None: # When the passed path is None, we just want the configuration # defaults, not actually loading the whole configuration. return {} if default_path is None: # This is most likely not being used from salt, ie, could be salt-cloud # or salt-api which have not yet migrated to the new default_path # argument. Let's issue a warning message that the environ vars won't # work. import inspect previous_frame = inspect.getframeinfo(inspect.currentframe().f_back) log.warning( 'The function \'{0}()\' defined in {1!r} is not yet using the ' 'new \'default_path\' argument to `salt.config.load_config()`. ' 'As such, the {2!r} environment variable will be ignored'.format( previous_frame.function, previous_frame.filename, env_var ) ) # In this case, maintain old behaviour default_path = DEFAULT_MASTER_OPTS['conf_file'] # Default to the environment variable path, if it exists env_path = os.environ.get(env_var, path) if not env_path or not os.path.isfile(env_path): env_path = path # If non-default path from `-c`, use that over the env variable if path != default_path: env_path = path path = env_path # If the configuration file is missing, attempt to copy the template, # after removing the first header line. if not os.path.isfile(path): template = '{0}.template'.format(path) if os.path.isfile(template): import salt.utils # TODO: Need to re-import, need to find out why log.debug('Writing {0} based on {1}'.format(path, template)) with salt.utils.fopen(path, 'w') as out: with salt.utils.fopen(template, 'r') as ifile: ifile.readline() # skip first line out.write(ifile.read()) if os.path.isfile(path): try: opts = _read_conf_file(path) opts['conf_file'] = path return opts except Exception as err: import salt.log msg = 'Error parsing configuration file: {0} - {1}' if salt.log.is_console_configured(): log.warn(msg.format(path, err)) else: print(msg.format(path, err)) else: log.debug('Missing configuration file: {0}'.format(path)) return {}
def _linux_gpu_data(): ''' num_gpus: int gpus: - vendor: nvidia|amd|ati|... model: string ''' lspci = salt.utils.which('lspci') if not lspci: log.info( 'The `lspci` binary is not available on the system. GPU grains ' 'will not be available.') return {} elif __opts__.get('enable_gpu_grains', None) is False: log.info( 'Skipping lspci call because enable_gpu_grains was set to False ' 'in the config. GPU grains will not be available.') return {} # dominant gpu vendors to search for (MUST be lowercase for matching below) known_vendors = ['nvidia', 'amd', 'ati', 'intel'] devs = [] try: lspci_out = __salt__['cmd.run']('lspci -vmm') cur_dev = {} error = False # Add a blank element to the lspci_out.splitlines() list, # otherwise the last device is not evaluated as a cur_dev and ignored. lspci_list = lspci_out.splitlines() lspci_list.append('') for line in lspci_list: # check for record-separating empty lines if line == '': if cur_dev.get('Class', '') == 'VGA compatible controller': devs.append(cur_dev) # XXX; may also need to search for "3D controller" cur_dev = {} continue if re.match(r'^\w+:\s+.*', line): key, val = line.split(':', 1) cur_dev[key.strip()] = val.strip() else: error = True log.debug('Unexpected lspci output: \'{0}\''.format(line)) if error: log.warn('Error loading grains, unexpected linux_gpu_data output, ' 'check that you have a valid shell configured and ' 'permissions to run lspci command') except OSError: pass gpus = [] for gpu in devs: vendor_strings = gpu['Vendor'].lower().split() # default vendor to 'unknown', overwrite if we match a known one vendor = 'unknown' for name in known_vendors: # search for an 'expected' vendor name in the list of strings if name in vendor_strings: vendor = name break gpus.append({'vendor': vendor, 'model': gpu['Device']}) grains = {} grains['num_gpus'] = len(gpus) grains['gpus'] = gpus return grains