Merge branch '2016.3' into 'carbon'

Conflicts:
  - salt/fileserver/__init__.py
  - setup.py
  - tests/integration/modules/git.py
This commit is contained in:
rallytime 2016-09-14 09:15:29 -06:00
commit 95dbe1ade4
12 changed files with 124 additions and 29 deletions

BIN
doc/_static/snapshot_manager.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 297 KiB

View file

@ -581,6 +581,32 @@ Example of a minimal profile:
cluster: 'Prod'
Cloning from a Snapshot
=======================
.. versionadded:: Carbon
Cloning a template works similar to cloning a VM except for the fact that
a snapshot number must be provided.
Example of a minimal profile:
.. code-block:: yaml
my-template-clone:
provider: vcenter01
clonefrom: 'salt_vm'
snapshot: 3
.. image:: /_static/snapshot_manager.png
:align: center
:scale: 70%
.. note::
The previous diagram shows how to identify the snapshot number. Selected
(third snapshot) is number 3.
Creating a VM
=============

View file

@ -7,3 +7,4 @@ Version 2016.3.4 is a bugfix release for :doc:`2016.3.0
- The `disk.wipe` execution module function has been modified
so that it correctly wipes a disk.
- Add ability to clone from a snapshot to the VMWare salt-cloud driver.

View file

@ -132,6 +132,7 @@ from salt.exceptions import SaltCloudSystemExit
# Import salt cloud libs
import salt.config as config
from salt.ext.six.moves import range
# Attempt to import pyVim and pyVmomi libs
ESX_5_5_NAME_PORTION = 'VMware ESXi 5.5'
@ -2287,6 +2288,18 @@ def create(vm_):
raise SaltCloudSystemExit(
'The VM/template that you have specified under clonefrom does not exist.'
)
snapshot = None
if clone_type == 'vm' and 'snapshot' in vm_:
num = int(vm_['snapshot']) - 1
snapshot = object_ref.rootSnapshot[0]
# Drill down to the correct snapshot number
for _ in range(num):
try:
snapshot = snapshot.childSnapshot[0]
except IndexError:
raise SaltCloudSystemExit('Specified snapshot'
' does not exist.')
else:
clone_type = None
object_ref = None
@ -2429,12 +2442,20 @@ def create(vm_):
config_spec.extraConfig.append(option)
if 'clonefrom' in vm_:
# Create the clone specs
clone_spec = vim.vm.CloneSpec(
template=template,
location=reloc_spec,
config=config_spec
)
if not snapshot:
# Create the clone specs
clone_spec = vim.vm.CloneSpec(
template=template,
location=reloc_spec,
config=config_spec
)
else:
clone_spec = vim.vm.CloneSpec(
template=template,
location=reloc_spec,
config=config_spec,
snapshot=snapshot
)
if customization and (devices and 'network' in list(devices.keys())):
global_ip = vim.vm.customization.GlobalIPSettings()

View file

@ -57,6 +57,7 @@ log = logging.getLogger(__name__)
# Import third party libs
try:
import boto
import boto.ec2 # pylint: enable=unused-import
# connection settings were added in 2.33.0
required_boto_version = '2.33.0'
if (_LooseVersion(boto.__version__) <
@ -64,7 +65,6 @@ try:
msg = 'boto_elb requires boto {0}.'.format(required_boto_version)
logging.debug(msg)
raise ImportError()
import boto.ec2
from boto.ec2.elb import HealthCheck
from boto.ec2.elb.attributes import AccessLogAttribute
from boto.ec2.elb.attributes import ConnectionDrainingAttribute

View file

@ -316,6 +316,11 @@ if WITH_SETUPTOOLS:
self.run_command('install-pycrypto-windows')
self.distribution.salt_installing_pycrypto_windows = None
# Install PyYAML
self.distribution.salt_installing_pyyaml_windows = True
self.run_command('install-pyyaml-windows')
self.distribution.salt_installing_pyyaml_windows = None
# Download the required DLLs
self.distribution.salt_download_windows_dlls = True
self.run_command('download-windows-dlls')
@ -389,6 +394,37 @@ class InstallPyCryptoWindowsWheel(Command):
call_subprocess(call_arguments)
class InstallCompiledPyYaml(Command):
description = 'Install PyYAML on Windows'
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
if getattr(self.distribution, 'salt_installing_pyyaml_windows', None) is None:
print('This command is not meant to be called on it\'s own')
exit(1)
import platform
from pip.utils import call_subprocess
from pip.utils.logging import indent_log
platform_bits, _ = platform.architecture()
call_arguments = ['easy_install', '-Z']
if platform_bits == '64bit':
call_arguments.append(
'http://repo.saltstack.com/windows/dependencies/64/PyYAML-3.11.win-amd64-py2.7.exe'
)
else:
call_arguments.append(
'http://repo.saltstack.com/windows/dependencies/32/PyYAML-3.11.win-amd64-py2.7.exe'
)
with indent_log():
call_subprocess(call_arguments)
class DownloadWindowsDlls(Command):
description = 'Download required DLL\'s for windows'
@ -406,14 +442,14 @@ class DownloadWindowsDlls(Command):
import platform
from pip.utils.logging import indent_log
platform_bits, _ = platform.architecture()
url = 'https://repo.saltstack.com/windows/dependencies/{bits}/{fname}32.dll'
dest = os.path.join(os.path.dirname(sys.executable), '{fname}32.dll')
url = 'http://repo.saltstack.com/windows/dependencies/{bits}/{fname}.dll'
dest = os.path.join(os.path.dirname(sys.executable), '{fname}.dll')
with indent_log():
for fname in ('libeay', 'ssleay'):
for fname in ('libeay32', 'ssleay32', 'libsodium', 'msvcr120'):
furl = url.format(bits=platform_bits[:2], fname=fname)
fdest = dest.format(fname=fname)
if not os.path.exists(fdest):
log.info('Downloading {0}32.dll to {1} from {2}'.format(fname, fdest, furl))
log.info('Downloading {0}.dll to {1} from {2}'.format(fname, fdest, furl))
try:
import requests
from contextlib import closing
@ -426,7 +462,7 @@ class DownloadWindowsDlls(Command):
wfh.flush()
else:
log.error(
'Failed to download {0}32.dll to {1} from {2}'.format(
'Failed to download {0}.dll to {1} from {2}'.format(
fname, fdest, furl
)
)
@ -451,7 +487,7 @@ class DownloadWindowsDlls(Command):
wfh.flush()
else:
log.error(
'Failed to download {0}32.dll to {1} from {2}'.format(
'Failed to download {0}.dll to {1} from {2}'.format(
fname, fdest, furl
)
)
@ -723,6 +759,10 @@ class Install(install):
self.distribution.salt_installing_pycrypto_windows = True
self.run_command('install-pycrypto-windows')
self.distribution.salt_installing_pycrypto_windows = None
# Install PyYAML
self.distribution.salt_installing_pyyaml_windows = True
self.run_command('install-pyyaml-windows')
self.distribution.salt_installing_pyyaml_windows = None
# Download the required DLLs
self.distribution.salt_download_windows_dlls = True
self.run_command('download-windows-dlls')
@ -855,6 +895,7 @@ class SaltDistribution(distutils.dist.Distribution):
'install_lib': InstallLib})
if IS_WINDOWS_PLATFORM:
self.cmdclass.update({'install-pycrypto-windows': InstallPyCryptoWindowsWheel,
'install-pyyaml-windows': InstallCompiledPyYaml,
'download-windows-dlls': DownloadWindowsDlls})
if __saltstack_version__.info < (2015, 8): # pylint: disable=undefined-variable
self.cmdclass.update({'install-m2crypto-windows': InstallM2CryptoWindows})

View file

@ -53,14 +53,15 @@ def __has_required_azure():
'''
Returns True/False if the required version of the Azure SDK is installed.
'''
if hasattr(azure, '__version__'):
version = LooseVersion(azure.__version__)
else:
version = LooseVersion(azure.common.__version__)
if HAS_AZURE is True and REQUIRED_AZURE <= version:
return True
else:
return False
if HAS_AZURE:
if hasattr(azure, '__version__'):
version = LooseVersion(azure.__version__)
else:
version = LooseVersion(azure.common.__version__)
if REQUIRED_AZURE <= version:
return True
return False
@skipIf(HAS_AZURE is False, 'These tests require the Azure Python SDK to be installed.')

View file

@ -37,12 +37,15 @@ log = logging.getLogger(__name__)
def _git_version():
git_version = subprocess.Popen(
['git', '--version'],
shell=False,
close_fds=False if salt.utils.is_windows else True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE).communicate()[0]
try:
git_version = subprocess.Popen(
['git', '--version'],
shell=False,
close_fds=False if salt.utils.is_windows else True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE).communicate()[0]
except OSError:
return False
if not git_version:
log.debug('Git not installed')
return False

View file

@ -119,7 +119,6 @@ class PillarModuleTest(integration.ModuleCase):
from pillar.items
'''
get_items = self.run_function('pillar.items')
self.assertDictContainsSubset({'info': 'bar'}, get_items)
self.assertDictContainsSubset({'monty': 'python'}, get_items)
self.assertDictContainsSubset(
{'knights': ['Lancelot', 'Galahad', 'Bedevere', 'Robin']},

View file

@ -20,6 +20,7 @@ import integration
import salt.utils
@skip_if_binaries_missing('git')
class GitTest(integration.ModuleCase, integration.SaltReturnAssertsMixIn):
'''
Validate the git state
@ -310,7 +311,6 @@ class GitTest(integration.ModuleCase, integration.SaltReturnAssertsMixIn):
finally:
shutil.rmtree(name, ignore_errors=True)
@skip_if_binaries_missing('git')
def test_config_set_value_with_space_character(self):
'''
git.config

View file

@ -23,6 +23,7 @@ import salt.loader
from salt.ext.six.moves import range # pylint: disable=redefined-builtin
try:
import boto
import boto.ec2 # pylint: enable=unused-import
HAS_BOTO = True
except ImportError:
HAS_BOTO = False

View file

@ -978,6 +978,7 @@ class FileTestCase(TestCase):
# 'comment' function tests: 1
@destructiveTest
@patch.object(os.path, 'exists', MagicMock(return_value=True))
def test_comment(self):
'''
Test to comment out specified lines in a file.
@ -1033,6 +1034,7 @@ class FileTestCase(TestCase):
# 'uncomment' function tests: 1
@destructiveTest
@patch.object(os.path, 'exists', MagicMock(return_value=True))
def test_uncomment(self):
'''
Test to uncomment specified commented lines in a file