mirror of
https://github.com/valitydev/salt.git
synced 2024-11-08 09:23:56 +00:00
Merge branch 'develop' into develop
This commit is contained in:
commit
1c03d93013
@ -13,7 +13,6 @@ as those returned here
|
||||
# Import python libs
|
||||
from __future__ import absolute_import
|
||||
import os
|
||||
import json
|
||||
import socket
|
||||
import sys
|
||||
import glob
|
||||
@ -936,8 +935,6 @@ def _virtual(osdata):
|
||||
zone = __salt__['cmd.run']('{0}'.format(zonename))
|
||||
if zone != 'global':
|
||||
grains['virtual'] = 'zone'
|
||||
if salt.utils.platform.is_smartos_zone():
|
||||
grains.update(_smartos_zone_data())
|
||||
# Check if it's a branded zone (i.e. Solaris 8/9 zone)
|
||||
if isdir('/.SUNWnative'):
|
||||
grains['virtual'] = 'zone'
|
||||
@ -1671,8 +1668,6 @@ def os_data():
|
||||
])
|
||||
# store a untouched copy of the timestamp in osrelease_stamp
|
||||
grains['osrelease_stamp'] = uname_v
|
||||
if salt.utils.platform.is_smartos_globalzone():
|
||||
grains.update(_smartos_computenode_data())
|
||||
elif os.path.isfile('/etc/release'):
|
||||
with salt.utils.files.fopen('/etc/release', 'r') as fp_:
|
||||
rel_data = fp_.read()
|
||||
@ -2371,95 +2366,6 @@ def _hw_data(osdata):
|
||||
return grains
|
||||
|
||||
|
||||
def _smartos_computenode_data():
|
||||
'''
|
||||
Return useful information from a SmartOS compute node
|
||||
'''
|
||||
# Provides:
|
||||
# vms_total
|
||||
# vms_running
|
||||
# vms_stopped
|
||||
# sdc_version
|
||||
# vm_capable
|
||||
# vm_hw_virt
|
||||
|
||||
if salt.utils.platform.is_proxy():
|
||||
return {}
|
||||
|
||||
grains = {}
|
||||
|
||||
# *_vms grains
|
||||
grains['computenode_vms_total'] = len(__salt__['cmd.run']('vmadm list -p').split("\n"))
|
||||
grains['computenode_vms_running'] = len(__salt__['cmd.run']('vmadm list -p state=running').split("\n"))
|
||||
grains['computenode_vms_stopped'] = len(__salt__['cmd.run']('vmadm list -p state=stopped').split("\n"))
|
||||
|
||||
# sysinfo derived grains
|
||||
sysinfo = json.loads(__salt__['cmd.run']('sysinfo'))
|
||||
grains['computenode_sdc_version'] = sysinfo['SDC Version']
|
||||
grains['computenode_vm_capable'] = sysinfo['VM Capable']
|
||||
if sysinfo['VM Capable']:
|
||||
grains['computenode_vm_hw_virt'] = sysinfo['CPU Virtualization']
|
||||
|
||||
# sysinfo derived smbios grains
|
||||
grains['manufacturer'] = sysinfo['Manufacturer']
|
||||
grains['productname'] = sysinfo['Product']
|
||||
grains['uuid'] = sysinfo['UUID']
|
||||
|
||||
return grains
|
||||
|
||||
|
||||
def _smartos_zone_data():
|
||||
'''
|
||||
Return useful information from a SmartOS zone
|
||||
'''
|
||||
# Provides:
|
||||
# pkgsrcversion
|
||||
# imageversion
|
||||
# pkgsrcpath
|
||||
# zonename
|
||||
# zoneid
|
||||
# hypervisor_uuid
|
||||
# datacenter
|
||||
|
||||
if salt.utils.platform.is_proxy():
|
||||
return {}
|
||||
|
||||
grains = {}
|
||||
|
||||
pkgsrcversion = re.compile('^release:\\s(.+)')
|
||||
imageversion = re.compile('Image:\\s(.+)')
|
||||
pkgsrcpath = re.compile('PKG_PATH=(.+)')
|
||||
if os.path.isfile('/etc/pkgsrc_version'):
|
||||
with salt.utils.files.fopen('/etc/pkgsrc_version', 'r') as fp_:
|
||||
for line in fp_:
|
||||
match = pkgsrcversion.match(line)
|
||||
if match:
|
||||
grains['pkgsrcversion'] = match.group(1)
|
||||
if os.path.isfile('/etc/product'):
|
||||
with salt.utils.files.fopen('/etc/product', 'r') as fp_:
|
||||
for line in fp_:
|
||||
match = imageversion.match(line)
|
||||
if match:
|
||||
grains['imageversion'] = match.group(1)
|
||||
if os.path.isfile('/opt/local/etc/pkg_install.conf'):
|
||||
with salt.utils.files.fopen('/opt/local/etc/pkg_install.conf', 'r') as fp_:
|
||||
for line in fp_:
|
||||
match = pkgsrcpath.match(line)
|
||||
if match:
|
||||
grains['pkgsrcpath'] = match.group(1)
|
||||
if 'pkgsrcversion' not in grains:
|
||||
grains['pkgsrcversion'] = 'Unknown'
|
||||
if 'imageversion' not in grains:
|
||||
grains['imageversion'] = 'Unknown'
|
||||
if 'pkgsrcpath' not in grains:
|
||||
grains['pkgsrcpath'] = 'Unknown'
|
||||
|
||||
grains['zonename'] = __salt__['cmd.run']('zonename')
|
||||
grains['zoneid'] = __salt__['cmd.run']('zoneadm list -p | awk -F: \'{ print $1 }\'', python_shell=True)
|
||||
|
||||
return grains
|
||||
|
||||
|
||||
def _zpool_data(grains):
|
||||
'''
|
||||
Provide grains about zpools
|
||||
|
196
salt/grains/smartos.py
Normal file
196
salt/grains/smartos.py
Normal file
@ -0,0 +1,196 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
SmartOS grain provider
|
||||
|
||||
:maintainer: Jorge Schrauwen <sjorge@blackdot.be>
|
||||
:maturity: new
|
||||
:depends: salt.utils, salt.ext.six, salt.module.cmdmod
|
||||
:platform: SmartOS
|
||||
|
||||
.. versionadded:: nitrogen
|
||||
|
||||
'''
|
||||
from __future__ import absolute_import
|
||||
|
||||
# Import python libs
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
import logging
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils.dictupdate
|
||||
import salt.utils.path
|
||||
import salt.utils.platform
|
||||
from salt.ext.six.moves import zip
|
||||
|
||||
# Solve the Chicken and egg problem where grains need to run before any
|
||||
# of the modules are loaded and are generally available for any usage.
|
||||
import salt.modules.cmdmod
|
||||
|
||||
__virtualname__ = 'smartos'
|
||||
__salt__ = {
|
||||
'cmd.run': salt.modules.cmdmod.run,
|
||||
}
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def __virtual__():
|
||||
'''
|
||||
Only load when we are on SmartOS
|
||||
'''
|
||||
if salt.utils.platform.is_smartos():
|
||||
return __virtualname__
|
||||
return False
|
||||
|
||||
|
||||
def _smartos_computenode_data():
|
||||
'''
|
||||
Return useful information from a SmartOS compute node
|
||||
'''
|
||||
# Provides:
|
||||
# vms_total
|
||||
# vms_running
|
||||
# vms_stopped
|
||||
# vms_type
|
||||
# sdc_version
|
||||
# vm_capable
|
||||
# vm_hw_virt
|
||||
|
||||
grains = {}
|
||||
|
||||
# collect vm data
|
||||
vms = {}
|
||||
for vm in __salt__['cmd.run']('vmadm list -p -o uuid,alias,state,type').split("\n"):
|
||||
vm = dict(list(zip(['uuid', 'alias', 'state', 'type'], vm.split(':'))))
|
||||
vms[vm['uuid']] = vm
|
||||
del vms[vm['uuid']]['uuid']
|
||||
|
||||
# set vm grains
|
||||
grains['computenode_vms_total'] = len(vms)
|
||||
grains['computenode_vms_running'] = 0
|
||||
grains['computenode_vms_stopped'] = 0
|
||||
grains['computenode_vms_type'] = {'KVM': 0, 'LX': 0, 'OS': 0}
|
||||
for vm in vms:
|
||||
if vms[vm]['state'].lower() == 'running':
|
||||
grains['computenode_vms_running'] += 1
|
||||
elif vms[vm]['state'].lower() == 'stopped':
|
||||
grains['computenode_vms_stopped'] += 1
|
||||
|
||||
if vms[vm]['type'] not in grains['computenode_vms_type']:
|
||||
# NOTE: be prepared for when bhyve gets its own type
|
||||
grains['computenode_vms_type'][vms[vm]['type']] = 0
|
||||
grains['computenode_vms_type'][vms[vm]['type']] += 1
|
||||
|
||||
# sysinfo derived grains
|
||||
sysinfo = json.loads(__salt__['cmd.run']('sysinfo'))
|
||||
grains['computenode_sdc_version'] = sysinfo['SDC Version']
|
||||
grains['computenode_vm_capable'] = sysinfo['VM Capable']
|
||||
if sysinfo['VM Capable']:
|
||||
grains['computenode_vm_hw_virt'] = sysinfo['CPU Virtualization']
|
||||
|
||||
# sysinfo derived smbios grains
|
||||
grains['manufacturer'] = sysinfo['Manufacturer']
|
||||
grains['productname'] = sysinfo['Product']
|
||||
grains['uuid'] = sysinfo['UUID']
|
||||
|
||||
return grains
|
||||
|
||||
|
||||
def _smartos_zone_data():
|
||||
'''
|
||||
Return useful information from a SmartOS zone
|
||||
'''
|
||||
# Provides:
|
||||
# zoneid
|
||||
# zonename
|
||||
# imageversion
|
||||
|
||||
grains = {
|
||||
'zoneid': __salt__['cmd.run']('zoneadm list -p | awk -F: \'{ print $1 }\'', python_shell=True),
|
||||
'zonename': __salt__['cmd.run']('zonename'),
|
||||
'imageversion': 'Unknown',
|
||||
}
|
||||
|
||||
imageversion = re.compile('Image:\\s(.+)')
|
||||
if os.path.isfile('/etc/product'):
|
||||
with salt.utils.files.fopen('/etc/product', 'r') as fp_:
|
||||
for line in fp_:
|
||||
match = imageversion.match(line)
|
||||
if match:
|
||||
grains['imageversion'] = match.group(1)
|
||||
|
||||
return grains
|
||||
|
||||
|
||||
def _smartos_zone_pkgsrc_data():
|
||||
'''
|
||||
SmartOS zone pkgsrc information
|
||||
'''
|
||||
# Provides:
|
||||
# pkgsrcversion
|
||||
# pkgsrcpath
|
||||
|
||||
grains = {
|
||||
'pkgsrcversion': 'Unknown',
|
||||
'pkgsrcpath': 'Unknown',
|
||||
}
|
||||
|
||||
pkgsrcversion = re.compile('^release:\\s(.+)')
|
||||
if os.path.isfile('/etc/pkgsrc_version'):
|
||||
with salt.utils.files.fopen('/etc/pkgsrc_version', 'r') as fp_:
|
||||
for line in fp_:
|
||||
match = pkgsrcversion.match(line)
|
||||
if match:
|
||||
grains['pkgsrcversion'] = match.group(1)
|
||||
|
||||
pkgsrcpath = re.compile('PKG_PATH=(.+)')
|
||||
if os.path.isfile('/opt/local/etc/pkg_install.conf'):
|
||||
with salt.utils.files.fopen('/opt/local/etc/pkg_install.conf', 'r') as fp_:
|
||||
for line in fp_:
|
||||
match = pkgsrcpath.match(line)
|
||||
if match:
|
||||
grains['pkgsrcpath'] = match.group(1)
|
||||
|
||||
return grains
|
||||
|
||||
|
||||
def _smartos_zone_pkgin_data():
|
||||
'''
|
||||
SmartOS zone pkgsrc information
|
||||
'''
|
||||
# Provides:
|
||||
# pkgin_repositories
|
||||
|
||||
grains = {
|
||||
'pkgin_repositories': [],
|
||||
}
|
||||
|
||||
pkginrepo = re.compile('^(?:https|http|ftp|file)://.*$')
|
||||
if os.path.isfile('/opt/local/etc/pkgin/repositories.conf'):
|
||||
with salt.utils.files.fopen('/opt/local/etc/pkgin/repositories.conf', 'r') as fp_:
|
||||
for line in fp_:
|
||||
if pkginrepo.match(line):
|
||||
grains['pkgin_repositories'].append(line)
|
||||
|
||||
return grains
|
||||
|
||||
|
||||
def smartos():
|
||||
'''
|
||||
Provide grains for SmartOS
|
||||
'''
|
||||
grains = {}
|
||||
|
||||
if salt.utils.platform.is_smartos_zone():
|
||||
grains = salt.utils.dictupdate.update(grains, _smartos_zone_data(), merge_lists=True)
|
||||
grains = salt.utils.dictupdate.update(grains, _smartos_zone_pkgsrc_data(), merge_lists=True)
|
||||
grains = salt.utils.dictupdate.update(grains, _smartos_zone_pkgin_data(), merge_lists=True)
|
||||
elif salt.utils.platform.is_smartos_globalzone():
|
||||
grains = salt.utils.dictupdate.update(grains, _smartos_computenode_data(), merge_lists=True)
|
||||
|
||||
return grains
|
||||
|
||||
|
||||
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
@ -1777,9 +1777,9 @@ def line(path, content=None, match=None, mode=None, location=None,
|
||||
|
||||
location
|
||||
Defines where to place content in the line. Note this option is only
|
||||
used when ``mode=insert`` is specified. If a location is passed in, it
|
||||
takes precedence over both the ``before`` and ``after`` kwargs. Valid
|
||||
locations are:
|
||||
used when ``mode=insert`` or ``mode=ensure`` is specified. If a location
|
||||
is passed in, it takes precedence over both the ``before`` and ``after``
|
||||
kwargs. Valid locations are:``
|
||||
|
||||
- start
|
||||
Place the content at the beginning of the file.
|
||||
@ -1930,63 +1930,83 @@ def line(path, content=None, match=None, mode=None, location=None,
|
||||
after = after and after.strip()
|
||||
before = before and before.strip()
|
||||
|
||||
if before and after:
|
||||
_assert_occurrence(body, before, 'before')
|
||||
_assert_occurrence(body, after, 'after')
|
||||
|
||||
a_idx = b_idx = -1
|
||||
idx = 0
|
||||
body = body.split(os.linesep)
|
||||
for _line in body:
|
||||
idx += 1
|
||||
if _line.find(before) > -1 and b_idx < 0:
|
||||
b_idx = idx
|
||||
if _line.find(after) > -1 and a_idx < 0:
|
||||
a_idx = idx
|
||||
|
||||
# Add
|
||||
if not b_idx - a_idx - 1:
|
||||
body = body[:a_idx] + [content] + body[b_idx - 1:]
|
||||
elif b_idx - a_idx - 1 == 1:
|
||||
if _starts_till(body[a_idx:b_idx - 1][0], content) > -1:
|
||||
body[a_idx] = _get_line_indent(body[a_idx - 1], content, indent)
|
||||
else:
|
||||
raise CommandExecutionError('Found more than one line between boundaries "before" and "after".')
|
||||
body = os.linesep.join(body)
|
||||
|
||||
elif before and not after:
|
||||
_assert_occurrence(body, before, 'before')
|
||||
body = body.split(os.linesep)
|
||||
if location:
|
||||
found = False
|
||||
out = []
|
||||
for idx in range(len(body)):
|
||||
if body[idx].find(before) > -1:
|
||||
prev = (idx > 0 and idx or 1) - 1
|
||||
out.append(_get_line_indent(body[prev], content, indent))
|
||||
if _starts_till(out[prev], content) > -1:
|
||||
del out[prev]
|
||||
out.append(body[idx])
|
||||
body = os.linesep.join(out)
|
||||
|
||||
elif not before and after:
|
||||
_assert_occurrence(body, after, 'after')
|
||||
body = body.split(os.linesep)
|
||||
skip = None
|
||||
out = []
|
||||
for idx in range(len(body)):
|
||||
if skip != body[idx]:
|
||||
out.append(body[idx])
|
||||
|
||||
if body[idx].find(after) > -1:
|
||||
next_line = idx + 1 < len(body) and body[idx + 1] or None
|
||||
if next_line is not None and _starts_till(next_line, content) > -1:
|
||||
skip = next_line
|
||||
out.append(_get_line_indent(body[idx], content, indent))
|
||||
body = os.linesep.join(out)
|
||||
|
||||
if body:
|
||||
for file_line in body.split(os.linesep):
|
||||
if file_line.find(match) > -1 and not file_line == content:
|
||||
out.append(_get_line_indent(file_line, content, indent))
|
||||
found = True
|
||||
elif file_line == content:
|
||||
out.append(file_line)
|
||||
found = True
|
||||
else:
|
||||
out.append(file_line)
|
||||
body = os.linesep.join(out)
|
||||
if not found:
|
||||
if location == 'start':
|
||||
body = os.linesep.join([content, body])
|
||||
elif location == 'end':
|
||||
body = os.linesep.join([body, _get_line_indent(body[-1], content, indent) if body else content])
|
||||
else:
|
||||
raise CommandExecutionError("Wrong conditions? "
|
||||
"Unable to ensure line without knowing "
|
||||
"where to put it before and/or after.")
|
||||
if before and after:
|
||||
_assert_occurrence(body, before, 'before')
|
||||
_assert_occurrence(body, after, 'after')
|
||||
|
||||
a_idx = b_idx = -1
|
||||
idx = 0
|
||||
body = body.split(os.linesep)
|
||||
for _line in body:
|
||||
idx += 1
|
||||
if _line.find(before) > -1 and b_idx < 0:
|
||||
b_idx = idx
|
||||
if _line.find(after) > -1 and a_idx < 0:
|
||||
a_idx = idx
|
||||
|
||||
# Add
|
||||
if not b_idx - a_idx - 1:
|
||||
body = body[:a_idx] + [content] + body[b_idx - 1:]
|
||||
elif b_idx - a_idx - 1 == 1:
|
||||
if _starts_till(body[a_idx:b_idx - 1][0], content) > -1:
|
||||
body[a_idx] = _get_line_indent(body[a_idx - 1], content, indent)
|
||||
else:
|
||||
raise CommandExecutionError('Found more than one line between boundaries "before" and "after".')
|
||||
body = os.linesep.join(body)
|
||||
|
||||
elif before and not after:
|
||||
_assert_occurrence(body, before, 'before')
|
||||
body = body.split(os.linesep)
|
||||
out = []
|
||||
for idx in range(len(body)):
|
||||
if body[idx].find(before) > -1:
|
||||
prev = (idx > 0 and idx or 1) - 1
|
||||
out.append(_get_line_indent(body[prev], content, indent))
|
||||
if _starts_till(out[prev], content) > -1:
|
||||
del out[prev]
|
||||
out.append(body[idx])
|
||||
body = os.linesep.join(out)
|
||||
|
||||
elif not before and after:
|
||||
_assert_occurrence(body, after, 'after')
|
||||
body = body.split(os.linesep)
|
||||
skip = None
|
||||
out = []
|
||||
for idx in range(len(body)):
|
||||
if skip != body[idx]:
|
||||
out.append(body[idx])
|
||||
|
||||
if body[idx].find(after) > -1:
|
||||
next_line = idx + 1 < len(body) and body[idx + 1] or None
|
||||
if next_line is not None and _starts_till(next_line, content) > -1:
|
||||
skip = next_line
|
||||
out.append(_get_line_indent(body[idx], content, indent))
|
||||
body = os.linesep.join(out)
|
||||
|
||||
else:
|
||||
raise CommandExecutionError("Wrong conditions? "
|
||||
"Unable to ensure line without knowing "
|
||||
"where to put it before and/or after.")
|
||||
|
||||
changed = body_before != hashlib.sha256(salt.utils.stringutils.to_bytes(body)).hexdigest()
|
||||
|
||||
|
@ -738,6 +738,68 @@ class FileModuleTestCase(TestCase, LoaderModuleMockMixin):
|
||||
saltenv='base')
|
||||
self.assertEqual(ret, 'This is a templated file.')
|
||||
|
||||
def test_line_ensure_location_start(self):
|
||||
'''
|
||||
Check that file.line uses ``location=start`` if a
|
||||
match is not found and replaces content if it is.
|
||||
'''
|
||||
# File DOESN'T contain the match
|
||||
with tempfile.NamedTemporaryFile(mode='w+b', delete=False) as tfile:
|
||||
tfile.write(salt.utils.to_bytes('first=foo' + os.linesep))
|
||||
tfile.flush()
|
||||
filemod.line(tfile.name,
|
||||
content='second=bar',
|
||||
match='second=',
|
||||
mode='ensure',
|
||||
location='start')
|
||||
expected = os.linesep.join(['second=bar', 'first=foo']) + os.linesep
|
||||
with salt.utils.files.fopen(tfile.name) as tfile2:
|
||||
self.assertEqual(tfile2.read(), expected)
|
||||
|
||||
# File DOES contain the match
|
||||
with tempfile.NamedTemporaryFile(mode='w+b', delete=False) as tfile:
|
||||
tfile.write(salt.utils.to_bytes(os.linesep.join(['first=foo', 'second=foo']) + os.linesep))
|
||||
tfile.flush()
|
||||
filemod.line(tfile.name,
|
||||
content='second=bar',
|
||||
match='second=',
|
||||
mode='ensure',
|
||||
location='start')
|
||||
expected = os.linesep.join(['first=foo', 'second=bar']) + os.linesep
|
||||
with salt.utils.files.fopen(tfile.name) as tfile2:
|
||||
self.assertEqual(tfile2.read(), expected)
|
||||
|
||||
def test_line_ensure_location_end(self):
|
||||
'''
|
||||
Check that file.line uses ``location=end`` if a
|
||||
match is not found and replaces content if it is.
|
||||
'''
|
||||
# File DOESN'T contain the match
|
||||
with tempfile.NamedTemporaryFile(mode='w+b', delete=False) as tfile:
|
||||
tfile.write(salt.utils.to_bytes('first=foo'))
|
||||
tfile.flush()
|
||||
filemod.line(tfile.name,
|
||||
content='second=bar',
|
||||
match='second=',
|
||||
mode='ensure',
|
||||
location='end')
|
||||
expected = os.linesep.join(['first=foo', 'second=bar'])
|
||||
with salt.utils.files.fopen(tfile.name) as tfile2:
|
||||
self.assertEqual(tfile2.read(), expected)
|
||||
|
||||
# File DOES contain the match
|
||||
with tempfile.NamedTemporaryFile(mode='w+b', delete=False) as tfile:
|
||||
tfile.write(salt.utils.to_bytes(os.linesep.join(['second=foo', 'first=foo']) + os.linesep))
|
||||
tfile.flush()
|
||||
filemod.line(tfile.name,
|
||||
content='second=bar',
|
||||
match='second=',
|
||||
mode='ensure',
|
||||
location='end')
|
||||
expected = os.linesep.join(['second=bar', 'first=foo']) + os.linesep
|
||||
with salt.utils.files.fopen(tfile.name) as tfile2:
|
||||
self.assertEqual(tfile2.read(), expected)
|
||||
|
||||
def test_replace_line_in_empty_file(self):
|
||||
'''
|
||||
Tests that when calling file.line with ``mode=replace``,
|
||||
|
Loading…
Reference in New Issue
Block a user