Merge branch 'develop' into develop

This commit is contained in:
Riley 2017-11-07 08:49:09 -05:00 committed by GitHub
commit 1c03d93013
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 336 additions and 152 deletions

View File

@ -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
View 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

View File

@ -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()

View File

@ -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``,