Merge branch 'badsid' of https://github.com/morganwillcock/salt into badsid

This commit is contained in:
Morgan Willcock 2017-11-12 12:35:14 +00:00
commit f3af106e33
31 changed files with 852 additions and 201 deletions

5
.gitignore vendored
View file

@ -91,3 +91,8 @@ tests/integration/cloud/providers/pki/minions
# Ignore tox virtualenvs
/.tox/
# Ignore kitchen stuff
.kitchen
.bundle
Gemfile.lock

187
.kitchen.yml Normal file
View file

@ -0,0 +1,187 @@
---
<% vagrant = system('which vagrant 2>/dev/null >/dev/null') %>
<% version = '2017.7.2' %>
<% platformsfile = ENV['SALT_KITCHEN_PLATFORMS'] || '.kitchen/platforms.yml' %>
<% driverfile = ENV['SALT_KITCHEN_DRIVER'] || '.kitchen/driver.yml' %>
<% if File.exists?(driverfile) %>
<%= ERB.new(File.read(driverfile)).result %>
<% else %>
driver:
name: docker
use_sudo: false
privileged: true
username: root
volume:
- /var/run/docker.sock:/docker.sock
cap_add:
- sys_admin
disable_upstart: false
provision_command:
- echo 'L /run/docker.sock - - - - /docker.sock' > /etc/tmpfiles.d/docker.conf
<% end %>
sudo: false
provisioner:
name: salt_solo
salt_install: bootstrap
salt_version: latest
salt_bootstrap_url: https://bootstrap.saltstack.com
salt_bootstrap_options: -X stable <%= version %>
log_level: info
require_chef: false
remote_states:
name: git://github.com/saltstack/salt-jenkins.git
branch: 2017.7
repo: git
testingdir: /testing
salt_copy_filter:
- .bundle
- .git
- .gitignore
- .kitchen
- .kitchen.yml
- Gemfile
- Gemfile.lock
- README.rst
- .travis.yml
state_top:
base:
"*":
- git.salt
- kitchen
<% if File.exists?(platformsfile) %>
<%= ERB.new(File.read(platformsfile)).result %>
<% else %>
platforms:
- name: fedora
driver_config:
image: fedora:latest
run_command: /usr/lib/systemd/systemd
provisioner:
salt_bootstrap_options: -X git v<%= version %> >/dev/null
- name: centos-7
driver_config:
run_command: /usr/lib/systemd/systemd
- name: centos-6
driver_config:
run_command: /sbin/init
provision_command:
- yum install -y upstart
provisioner:
salt_bootstrap_options: -P -y -x python2.7 -X git v<%= version %> >/dev/null
- name: ubuntu-rolling
driver_config:
image: ubuntu:rolling
run_command: /lib/systemd/systemd
provisioner:
salt_bootstrap_url: https://raw.githubusercontent.com/saltstack/salt-bootstrap/develop/bootstrap-salt.sh
- name: ubuntu-16.04
driver_config:
run_command: /lib/systemd/systemd
- name: ubuntu-14.04
driver_config:
run_command: /sbin/init
provision_command:
- rm -f /sbin/initctl
- dpkg-divert --local --rename --remove /sbin/initctl
- name: debian-8
driver_config:
run_command: /lib/systemd/systemd
provision_command:
- apt-get install -y dbus
- echo 'L /run/docker.sock - - - - /docker.sock' > /etc/tmpfiles.d/docker.conf
- name: debian-9
driver_config:
run_command: /lib/systemd/systemd
- name: arch
driver_config:
image: base/archlinux
run_command: /usr/lib/systemd/systemd
provision_command:
- pacman -Syu --noconfirm systemd
- systemctl enable sshd
- echo 'L /run/docker.sock - - - - /docker.sock' > /etc/tmpfiles.d/docker.conf
provisioner:
salt_bootstrap_options: -X git v<%= version %> >/dev/null
- name: opensuse
driver_config:
run_command: /usr/lib/systemd/systemd
provision_command:
- systemctl enable sshd.service
- echo 'L /run/docker.sock - - - - /docker.sock' > /etc/tmpfiles.d/docker.conf
provisioner:
salt_bootstrap_options: -X git v<%= version %> >/dev/null
<% if vagrant != false %>
- name: windows-2012r2
driver:
box: mwrock/Windows2012R2
communicator: winrm
name: vagrant
gui: true
username: administrator
password: Pass@word1
provisioner:
init_environment: |
Clear-Host
$AddedLocation ="c:\salt"
$Reg = "Registry::HKLM\System\CurrentControlSet\Control\Session Manager\Environment"
$OldPath = (Get-ItemProperty -Path "$Reg" -Name PATH).Path
$NewPath= $OldPath + ; + $AddedLocation
Set-ItemProperty -Path "$Reg" -Name PATH Value $NewPath
salt_bootstrap_url: https://raw.githubusercontent.com/saltstack/salt-bootstrap/develop/bootstrap-salt.ps1
salt_bootstrap_options: ''
- name: windows-2016
driver:
box: mwrock/Windows2016
communicator: winrm
name: vagrant
username: Vagrant
password: vagrant
gui: true
provisioner:
init_environment: |
Clear-Host
$AddedLocation ="c:\salt;c:\salt\bin\Scripts"
$Reg = "Registry::HKLM\System\CurrentControlSet\Control\Session Manager\Environment"
$OldPath = (Get-ItemProperty -Path "$Reg" -Name PATH).Path
$NewPath= $OldPath + ; + $AddedLocation
Set-ItemProperty -Path "$Reg" -Name PATH Value $NewPath
salt_bootstrap_url: https://raw.githubusercontent.com/saltstack/salt-bootstrap/develop/bootstrap-salt.ps1
salt_bootstrap_options: ''
<% end %>
<% end %>
suites:
- name: py2
provisioner:
pillars:
top.sls:
base:
"*":
- jenkins
jenkins.sls:
testing_dir: /tmp/kitchen/testing
clone_repo: false
salttesting_namespec: salttesting==2017.6.1
- name: py3
provisioner:
pillars:
top.sls:
base:
"*":
- jenkins
jenkins.sls:
testing_dir: /tmp/kitchen/testing
clone_repo: false
py3: true
salttesting_namespec: salttesting==2017.6.1
verifier:
name: shell
remote_exec: true
sudo: false
live_stream: {}
<% if ENV['TESTOPTS'].nil? %>
command: '$(kitchen) /tmp/kitchen/testing/tests/runtests.py --run-destructive --sysinfo --transport=zeromq --output-columns=80 --ssh --coverage-xml=/tmp/coverage.xml --xml=/tmp/xml-unittests-output'
<% else %>
command: '$(kitchen) /tmp/kitchen/testing/tests/runtests.py --run-destructive --output-columns 80 <%= ENV["TESTOPTS"] %>'
<% end %>

23
Gemfile Normal file
View file

@ -0,0 +1,23 @@
# This file is only used for running the test suite with kitchen-salt.
source "https://rubygems.org"
gem "test-kitchen"
gem "kitchen-salt", :git => 'https://github.com/saltstack/kitchen-salt.git'
gem 'git'
group :docker do
gem 'kitchen-docker', :git => 'https://github.com/test-kitchen/kitchen-docker.git'
end
group :opennebula do
gem 'kitchen-opennebula', :git => 'https://github.com/gtmanfred/kitchen-opennebula.git'
gem 'xmlrpc'
end
group :windows do
gem 'vagrant-wrapper'
gem 'kitchen-vagrant'
gem 'winrm', '~>2.0'
gem 'winrm-fs', '~>1.0'
end

View file

@ -19,14 +19,18 @@ Salt SSH allows for salt routines to be executed using only SSH for transport
Options
=======
.. program:: salt-ssh
.. include:: _includes/common-options.rst
.. option:: --hard-crash
Raise any original exception rather than exiting gracefully. Default: False.
.. option:: -r, --raw, --raw-shell
Execute a raw shell command.
.. option:: --priv
Specify the SSH private key file to be used for authentication.
.. option:: --roster
Define which roster system to use, this defines if a database backend,
@ -53,38 +57,117 @@ Options
the more running process the faster communication should be, default
is 25.
.. option:: --extra-filerefs=EXTRA_FILEREFS
Pass in extra files to include in the state tarball.
.. option:: --min-extra-modules=MIN_EXTRA_MODS
One or comma-separated list of extra Python modulesto be included
into Minimal Salt.
.. option:: --thin-extra-modules=THIN_EXTRA_MODS
One or comma-separated list of extra Python modulesto be included
into Thin Salt.
.. option:: -v, --verbose
Turn on command verbosity, display jid.
.. option:: -s, --static
Return the data from minions as a group after they all return.
.. option:: -w, --wipe
Remove the deployment of the salt files when done executing.
.. option:: -W, --rand-thin-dir
Select a random temp dir to deploy on the remote system. The dir
will be cleaned after the execution.
.. option:: -t, --regen-thin, --thin
Trigger a thin tarball regeneration. This is needed if custom
grains/modules/states have been added or updated.
.. option:: --python2-bin=PYTHON2_BIN
Path to a python2 binary which has salt installed.
.. option:: --python3-bin=PYTHON3_BIN
Path to a python3 binary which has salt installed.
.. option:: --jid=JID
Pass a JID to be used instead of generating one.
Authentication Options
----------------------
.. option:: --priv=SSH_PRIV
Specify the SSH private key file to be used for authentication.
.. option:: -i, --ignore-host-keys
Disables StrictHostKeyChecking to relax acceptance of new and unknown
host keys.
By default ssh host keys are honored and connections will ask for
approval. Use this option to disable StrictHostKeyChecking.
.. option:: --no-host-keys
Fully ignores ssh host keys which by default are honored and connections
would ask for approval. Useful if the host key of a remote server has
would ask for approval. Useful if the host key of a remote server has
changed and would still error with --ignore-host-keys.
.. option:: --user=SSH_USER
Set the default user to attempt to use when authenticating.
.. option:: --passwd
Set the default password to attempt to use when authenticating.
.. option:: --askpass
Interactively ask for the SSH password with no echo - avoids password
in process args and stored in history.
.. option:: --key-deploy
Set this flag to attempt to deploy the authorized ssh key with all
minions. This combined with --passwd can make initial deployment of keys
very fast and easy.
.. program:: salt
.. option:: --identities-only
.. include:: _includes/common-options.rst
Use the only authentication identity files configured in the ssh_config
files. See IdentitiesOnly flag in man ssh_config.
.. include:: _includes/target-selection-ssh.rst
.. option:: --sudo
Run command via sudo.
Scan Roster Options
-------------------
.. option:: --scan-ports=SSH_SCAN_PORTS
Comma-separated list of ports to scan in the scan roster.
.. option:: --scan-timeout=SSH_SCAN_TIMEOUT
Scanning socket timeout for the scan roster.
.. include:: _includes/logging-options.rst
.. |logfile| replace:: /var/log/salt/ssh
.. |loglevel| replace:: ``warning``
.. include:: _includes/target-selection-ssh.rst
.. include:: _includes/output-options.rst

View file

@ -202,7 +202,7 @@ this.
# /srv/salt/orch/deploy.sls
{% set servers = salt['pillar.get']('servers', 'test') %}
{% set master = salt['pillat.get']('master', 'salt') %}
{% set master = salt['pillar.get']('master', 'salt') %}
create_instance:
salt.runner:
- name: cloud.profile

View file

@ -498,16 +498,16 @@ def tar(options, tarfile, sources=None, dest=None,
.. code-block:: bash
salt '*' archive.tar -cjvf /tmp/salt.tar.bz2 {{grains.saltpath}} template=jinja
salt '*' archive.tar cjvf /tmp/salt.tar.bz2 {{grains.saltpath}} template=jinja
CLI Examples:
.. code-block:: bash
# Create a tarfile
salt '*' archive.tar -cjvf /tmp/tarfile.tar.bz2 /tmp/file_1,/tmp/file_2
salt '*' archive.tar cjvf /tmp/tarfile.tar.bz2 /tmp/file_1,/tmp/file_2
# Create a tarfile using globbing (2017.7.0 and later)
salt '*' archive.tar -cjvf /tmp/tarfile.tar.bz2 '/tmp/file_*'
salt '*' archive.tar cjvf /tmp/tarfile.tar.bz2 '/tmp/file_*'
# Unpack a tarfile
salt '*' archive.tar xf foo.tar dest=/target/directory
'''

View file

@ -51,6 +51,7 @@ import datetime
import logging
import json
import sys
import time
import email.mime.multipart
log = logging.getLogger(__name__)
@ -675,11 +676,23 @@ def get_scaling_policy_arn(as_group, scaling_policy_name, region=None,
salt '*' boto_asg.get_scaling_policy_arn mygroup mypolicy
'''
conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
policies = conn.get_all_policies(as_group=as_group)
for policy in policies:
if policy.name == scaling_policy_name:
return policy.policy_arn
log.error('Could not convert: {0}'.format(as_group))
retries = 30
while retries > 0:
retries -= 1
try:
policies = conn.get_all_policies(as_group=as_group)
for policy in policies:
if policy.name == scaling_policy_name:
return policy.policy_arn
log.error('Could not convert: {0}'.format(as_group))
return None
except boto.exception.BotoServerError as e:
if e.error_code != 'Throttling':
raise
log.debug('Throttled by API, will retry in 5 seconds')
time.sleep(5)
log.error('Maximum number of retries exceeded')
return None
@ -761,11 +774,18 @@ def get_instances(name, lifecycle_state="InService", health_status="Healthy",
# get full instance info, so that we can return the attribute
instances = ec2_conn.get_only_instances(instance_ids=instance_ids)
if attributes:
return [[getattr(instance, attr).encode("ascii") for attr in attributes] for instance in instances]
return [[_convert_attribute(instance, attr) for attr in attributes] for instance in instances]
else:
# properly handle case when not all instances have the requested attribute
return [getattr(instance, attribute).encode("ascii") for instance in instances if getattr(instance, attribute)]
return [getattr(instance, attribute).encode("ascii") for instance in instances]
return [_convert_attribute(instance, attribute) for instance in instances if getattr(instance, attribute)]
def _convert_attribute(instance, attribute):
if attribute == "tags":
tags = dict(getattr(instance, attribute))
return {key.encode("utf-8"): value.encode("utf-8") for key, value in six.iteritems(tags)}
return getattr(instance, attribute).encode("ascii")
def enter_standby(name, instance_ids, should_decrement_desired_capacity=False,

View file

@ -910,8 +910,8 @@ def compare_container(first, second, ignore=None):
ret.setdefault(conf_dict, {})[item] = {'old': image1, 'new': image2}
else:
if item == 'Links':
val1 = _scrub_links(val1, first)
val2 = _scrub_links(val2, second)
val1 = sorted(_scrub_links(val1, first))
val2 = sorted(_scrub_links(val2, second))
if val1 != val2:
ret.setdefault(conf_dict, {})[item] = {'old': val1, 'new': val2}
# Check for optionally-present items that were in the second container
@ -933,8 +933,8 @@ def compare_container(first, second, ignore=None):
ret.setdefault(conf_dict, {})[item] = {'old': image1, 'new': image2}
else:
if item == 'Links':
val1 = _scrub_links(val1, first)
val2 = _scrub_links(val2, second)
val1 = sorted(_scrub_links(val1, first))
val2 = sorted(_scrub_links(val2, second))
if val1 != val2:
ret.setdefault(conf_dict, {})[item] = {'old': val1, 'new': val2}
return ret

View file

@ -164,7 +164,7 @@ def _setup_conn(**kwargs):
if client_key_file:
kubernetes.client.configuration.key_file = client_key_file
if client_key:
elif client_key:
with tempfile.NamedTemporaryFile(prefix='salt-kube-', delete=False) as k:
k.write(base64.b64decode(client_key))
kubernetes.client.configuration.key_file = k.name

View file

@ -9,7 +9,7 @@ Module to provide redis functionality to Salt
.. code-block:: yaml
redis.host: 'localhost'
redis.host: 'salt'
redis.port: 6379
redis.db: 0
redis.password: None

View file

@ -40,6 +40,7 @@ Current known limitations
# Import python libs
from __future__ import absolute_import
from __future__ import unicode_literals
import io
import os
import logging
@ -4082,7 +4083,7 @@ def _write_regpol_data(data_to_write,
gpt_ini_data = ''
if os.path.exists(gpt_ini_path):
with salt.utils.fopen(gpt_ini_path, 'rb') as gpt_file:
gpt_ini_data = gpt_file.read()
gpt_ini_data = salt.utils.to_str(gpt_file.read())
if not _regexSearchRegPolData(r'\[General\]\r\n', gpt_ini_data):
gpt_ini_data = '[General]\r\n' + gpt_ini_data
if _regexSearchRegPolData(r'{0}='.format(re.escape(gpt_extension)), gpt_ini_data):
@ -4137,7 +4138,7 @@ def _write_regpol_data(data_to_write,
gpt_ini_data[general_location.end():])
if gpt_ini_data:
with salt.utils.fopen(gpt_ini_path, 'wb') as gpt_file:
gpt_file.write(gpt_ini_data)
gpt_file.write(salt.utils.to_bytes(gpt_ini_data))
except Exception as e:
msg = 'An error occurred attempting to write to {0}, the exception was {1}'.format(
gpt_ini_path, e)
@ -5375,7 +5376,7 @@ def set_(computer_policy=None, user_policy=None,
_regedits[regedit]['policy']['Registry']['Type'])
else:
_ret = __salt__['reg.delete_value'](
_regedits[regedit]['polic']['Registry']['Hive'],
_regedits[regedit]['policy']['Registry']['Hive'],
_regedits[regedit]['policy']['Registry']['Path'],
_regedits[regedit]['policy']['Registry']['Value'])
if not _ret:

View file

@ -444,8 +444,9 @@ def stop(name):
try:
win32serviceutil.StopService(name)
except pywintypes.error as exc:
raise CommandExecutionError(
'Failed To Stop {0}: {1}'.format(name, exc[2]))
if exc[0] != 1062:
raise CommandExecutionError(
'Failed To Stop {0}: {1}'.format(name, exc[2]))
attempts = 0
while info(name)['Status'] in ['Running', 'Stop Pending'] \

View file

@ -92,28 +92,31 @@ def halt(timeout=5, in_seconds=False):
Halt a running system.
Args:
timeout (int): Number of seconds before halting the system. Default is
5 seconds.
in_seconds (bool): Whether to treat timeout as seconds or minutes.
timeout (int):
Number of seconds before halting the system. Default is 5 seconds.
in_seconds (bool):
Whether to treat timeout as seconds or minutes.
.. versionadded:: 2015.8.0
Returns:
bool: True if successful, otherwise False
bool: ``True`` if successful, otherwise ``False``
CLI Example:
.. code-block:: bash
salt '*' system.halt 5
salt '*' system.halt 5 True
'''
return shutdown(timeout=timeout, in_seconds=in_seconds)
def init(runlevel): # pylint: disable=unused-argument
'''
Change the system runlevel on sysV compatible systems
Change the system runlevel on sysV compatible systems. Not applicable to
Windows
CLI Example:
@ -136,14 +139,18 @@ def poweroff(timeout=5, in_seconds=False):
Power off a running system.
Args:
timeout (int): Number of seconds before powering off the system. Default
is 5 seconds.
in_seconds (bool): Whether to treat timeout as seconds or minutes.
timeout (int):
Number of seconds before powering off the system. Default is 5
seconds.
in_seconds (bool):
Whether to treat timeout as seconds or minutes.
.. versionadded:: 2015.8.0
Returns:
bool: True if successful, otherwise False
bool: ``True`` if successful, otherwise ``False``
CLI Example:
@ -160,29 +167,35 @@ def reboot(timeout=5, in_seconds=False, wait_for_reboot=False, # pylint: disabl
Reboot a running system.
Args:
timeout (int): Number of minutes/seconds before rebooting the system.
Minutes vs seconds depends on the value of ``in_seconds``. Default
timeout (int):
The number of minutes/seconds before rebooting the system. Use of
minutes or seconds depends on the value of ``in_seconds``. Default
is 5 minutes.
in_seconds (bool): Whether to treat timeout as seconds or minutes.
in_seconds (bool):
``True`` will cause the ``timeout`` parameter to be in seconds.
``False`` will be in minutes. Default is ``False``.
.. versionadded:: 2015.8.0
wait_for_reboot (bool): Sleeps for timeout + 30 seconds after reboot has
been initiated. This may be useful for use in a highstate if a
reboot should be performed and the return data of the highstate is
not required. If return data is required, consider using the reboot
state instead of this module.
wait_for_reboot (bool)
``True`` will sleep for timeout + 30 seconds after reboot has been
initiated. This is useful for use in a highstate. For example, you
may have states that you want to apply only after the reboot.
Default is ``False``.
.. versionadded:: 2015.8.0
only_on_pending_reboot (bool): If this is set to True, then the reboot
will only proceed if the system reports a pending reboot. To
optionally reboot in a highstate, consider using the reboot state
instead of this module.
only_on_pending_reboot (bool):
If this is set to ``True``, then the reboot will only proceed
if the system reports a pending reboot. Setting this parameter to
``True`` could be useful when calling this function from a final
housekeeping state intended to be executed at the end of a state run
(using *order: last*). Default is ``False``.
Returns:
bool: True if successful (a reboot will occur), otherwise False
bool: ``True`` if successful (a reboot will occur), otherwise ``False``
CLI Example:
@ -191,20 +204,16 @@ def reboot(timeout=5, in_seconds=False, wait_for_reboot=False, # pylint: disabl
salt '*' system.reboot 5
salt '*' system.reboot 5 True
As example of invoking this function from within a final housekeeping state
is as follows:
Example:
Invoking this function from a final housekeeping state:
.. code-block:: yaml
final housekeeping:
final_housekeeping:
module.run:
- name: system.reboot
- only_on_pending_reboot: True
- order: last
'''
ret = shutdown(timeout=timeout, reboot=True, in_seconds=in_seconds,
only_on_pending_reboot=only_on_pending_reboot)
@ -221,50 +230,63 @@ def shutdown(message=None, timeout=5, force_close=True, reboot=False, # pylint:
Shutdown a running system.
Args:
message (str): A message to display to the user before shutting down.
timeout (int): The length of time that the shutdown dialog box should be
displayed, in seconds. While this dialog box is displayed, the
shutdown can be stopped by the shutdown_abort function.
message (str):
The message to display to the user before shutting down.
timeout (int):
The length of time (in seconds) that the shutdown dialog box should
be displayed. While this dialog box is displayed, the shutdown can
be aborted using the ``system.shutdown_abort`` function.
If timeout is not zero, InitiateSystemShutdown displays a dialog box
on the specified computer. The dialog box displays the name of the
user who called the function, displays the message specified by the
lpMessage parameter, and prompts the user to log off. The dialog box
beeps when it is created and remains on top of other windows in the
system. The dialog box can be moved but not closed. A timer counts
down the remaining time before a forced shutdown.
user who called the function, the message specified by the lpMessage
parameter, and prompts the user to log off. The dialog box beeps
when it is created and remains on top of other windows (system
modal). The dialog box can be moved but not closed. A timer counts
down the remaining time before the shutdown occurs.
If timeout is zero, the computer shuts down without displaying the
dialog box, and the shutdown cannot be stopped by shutdown_abort.
If timeout is zero, the computer shuts down immediately without
displaying the dialog box and cannot be stopped by
``system.shutdown_abort``.
Default is 5 minutes
in_seconds (bool): Whether to treat timeout as seconds or minutes.
in_seconds (bool):
``True`` will cause the ``timeout`` parameter to be in seconds.
``False`` will be in minutes. Default is ``False``.
.. versionadded:: 2015.8.0
force_close (bool): True to force close all open applications. False
displays a dialog box instructing the user to close the
applications.
force_close (bool):
``True`` will force close all open applications. ``False`` will
display a dialog box instructing the user to close open
applications. Default is ``True``.
reboot (bool): True restarts the computer immediately after shutdown.
False caches to disk and safely powers down the system.
reboot (bool):
``True`` restarts the computer immediately after shutdown. ``False``
powers down the system. Default is ``False``.
only_on_pending_reboot (bool): If this is set to True, then the shutdown
will only proceed if the system reports a pending reboot. To
optionally shutdown in a highstate, consider using the shutdown
state instead of this module.
only_on_pending_reboot (bool):
If ``True`` the shutdown will only proceed if there is a reboot
pending. ``False`` will shutdown the system. Default is ``False``.
Returns:
bool: True if successful (a shutdown or reboot will occur), otherwise
False
bool:
``True`` if successful (a shutdown or reboot will occur), otherwise
``False``
CLI Example:
.. code-block:: bash
salt '*' system.shutdown 5
salt '*' system.shutdown "System will shutdown in 5 minutes"
'''
if six.PY2:
message = _to_unicode(message)
@ -294,7 +316,7 @@ def shutdown_hard():
Shutdown a running system with no timeout or warning.
Returns:
bool: True if successful, otherwise False
bool: ``True`` if successful, otherwise ``False``
CLI Example:
@ -312,7 +334,7 @@ def shutdown_abort():
aborted.
Returns:
bool: True if successful, otherwise False
bool: ``True`` if successful, otherwise ``False``
CLI Example:
@ -337,7 +359,7 @@ def lock():
Lock the workstation.
Returns:
bool: True if successful, otherwise False
bool: ``True`` if successful, otherwise ``False``
CLI Example:
@ -353,12 +375,14 @@ def set_computer_name(name):
Set the Windows computer name
Args:
name (str): The new name to give the computer. Requires a reboot to take
effect.
name (str):
The new name to give the computer. Requires a reboot to take effect.
Returns:
dict: Returns a dictionary containing the old and new names if
successful. False if not.
dict:
Returns a dictionary containing the old and new names if successful.
``False`` if not.
CLI Example:
@ -389,7 +413,9 @@ def get_pending_computer_name():
error message will be logged to the minion log.
Returns:
str: The pending name if restart is pending, otherwise returns None.
str:
Returns the pending name if pending restart. Returns ``None`` if not
pending restart.
CLI Example:
@ -412,7 +438,7 @@ def get_computer_name():
Get the Windows computer name
Returns:
str: Returns the computer name if found. Otherwise returns False
str: Returns the computer name if found. Otherwise returns ``False``.
CLI Example:
@ -429,10 +455,12 @@ def set_computer_desc(desc=None):
Set the Windows computer description
Args:
desc (str): The computer description
desc (str):
The computer description
Returns:
bool: True if successful, otherwise False
str: Description if successful, otherwise ``False``
CLI Example:
@ -475,8 +503,8 @@ def get_system_info():
Get system information.
Returns:
dict: Returns a Dictionary containing information about the system to
include name, description, version, etc...
dict: Dictionary containing information about the system to include
name, description, version, etc...
CLI Example:
@ -529,7 +557,8 @@ def get_computer_desc():
Get the Windows computer description
Returns:
str: The computer description if found, otherwise False
str: Returns the computer description if found. Otherwise returns
``False``.
CLI Example:
@ -546,12 +575,12 @@ get_computer_description = salt.utils.alias_function(get_computer_desc, 'get_com
def get_hostname():
'''
.. versionadded:: 2016.3.0
Get the hostname of the windows minion
.. versionadded:: 2016.3.0
Returns:
str: The hostname of the windows minion
str: Returns the hostname of the windows minion
CLI Example:
@ -566,16 +595,16 @@ def get_hostname():
def set_hostname(hostname):
'''
.. versionadded:: 2016.3.0
Set the hostname of the windows minion, requires a restart before this will
be updated.
Set the hostname of the windows minion, requires a restart before this
will be updated.
.. versionadded:: 2016.3.0
Args:
hostname (str): The hostname to set
Returns:
bool: True if successful, otherwise False
bool: ``True`` if successful, otherwise ``False``
CLI Example:
@ -597,37 +626,41 @@ def join_domain(domain,
account_exists=False,
restart=False):
'''
Join a computer to an Active Directory domain. Requires reboot.
Join a computer to an Active Directory domain. Requires a reboot.
Args:
domain (str): The domain to which the computer should be joined, e.g.
domain (str):
The domain to which the computer should be joined, e.g.
``example.com``
username (str): Username of an account which is authorized to join
computers to the specified domain. Need to be either fully qualified
like ``user@domain.tld`` or simply ``user``
username (str):
Username of an account which is authorized to join computers to the
specified domain. Needs to be either fully qualified like
``user@domain.tld`` or simply ``user``
password (str): Password of the specified user
password (str):
Password of the specified user
account_ou (str): The DN of the OU below which the account for this
computer should be created when joining the domain, e.g.
account_ou (str):
The DN of the OU below which the account for this computer should be
created when joining the domain, e.g.
``ou=computers,ou=departm_432,dc=my-company,dc=com``
account_exists (bool): If set to ``True`` the computer will only join
the domain if the account already exists. If set to ``False`` the
computer account will be created if it does not exist, otherwise it
will use the existing account. Default is False.
account_exists (bool):
If set to ``True`` the computer will only join the domain if the
account already exists. If set to ``False`` the computer account
will be created if it does not exist, otherwise it will use the
existing account. Default is ``False``
restart (bool): Restarts the computer after a successful join
restart (bool):
``True`` will restart the computer after a successful join. Default
is ``False``
.. versionadded:: 2015.8.2/2015.5.7
Returns:
dict: Dictionary if successful
Raises:
CommandExecutionError: Raises an error if _join_domain returns anything
other than 0
dict: Returns a dictionary if successful, otherwise ``False``
CLI Example:
@ -741,33 +774,41 @@ def unjoin_domain(username=None,
disable=False,
restart=False):
r'''
Unjoin a computer from an Active Directory Domain. Requires restart.
Unjoin a computer from an Active Directory Domain. Requires a restart.
Args:
username (str): Username of an account which is authorized to manage
computer accounts on the domain. Need to be fully qualified like
``user@domain.tld`` or ``domain.tld\user``. If domain not specified,
the passed domain will be used. If computer account doesn't need to
be disabled, can be None.
password (str): Password of the specified user
username (str):
Username of an account which is authorized to manage computer
accounts on the domain. Needs to be a fully qualified name like
``user@domain.tld`` or ``domain.tld\user``. If the domain is not
specified, the passed domain will be used. If the computer account
doesn't need to be disabled after the computer is unjoined, this can
be ``None``.
domain (str): The domain from which to unjoin the computer. Can be None.
password (str):
The password of the specified user
workgroup (str): The workgroup to join the computer to. Default is
``WORKGROUP``
domain (str):
The domain from which to unjoin the computer. Can be ``None``
workgroup (str):
The workgroup to join the computer to. Default is ``WORKGROUP``
.. versionadded:: 2015.8.2/2015.5.7
disable (bool): Disable the computer account in Active Directory. True
to disable. Default is False
disable (bool):
``True`` to disable the computer account in Active Directory.
Default is ``False``
restart (bool): Restart the computer after successful unjoin
restart (bool):
``True`` will restart the computer after successful unjoin. Default
is ``False``
.. versionadded:: 2015.8.2/2015.5.7
Returns:
dict: Dictionary if successful, otherwise False
dict: Returns a dictionary if successful, otherwise ``False``
CLI Example:
@ -859,15 +900,16 @@ def get_domain_workgroup():
def _try_parse_datetime(time_str, fmts):
'''
Attempts to parse the input time_str as a date.
A helper function that attempts to parse the input time_str as a date.
Args:
time_str (str): A string representing the time
fmts (list): A list of date format strings
Returns:
datetime: A datetime object if parsed properly, otherwise None
datetime: Returns a datetime object if parsed properly, otherwise None
'''
result = None
for fmt in fmts:
@ -910,7 +952,9 @@ def set_system_time(newtime):
Set the system time.
Args:
newtime (str): The time to set. Can be any of the following formats.
newtime (str):
The time to set. Can be any of the following formats:
- HH:MM:SS AM/PM
- HH:MM AM/PM
@ -918,7 +962,7 @@ def set_system_time(newtime):
- HH:MM (24 hour)
Returns:
bool: True if successful, otherwise False
bool: ``True`` if successful, otherwise ``False``
CLI Example:
@ -951,24 +995,16 @@ def set_system_date_time(years=None,
system year will be used. (Used by set_system_date and set_system_time)
Args:
years (int): Years digit, ie: 2015
months (int): Months digit: 1 - 12
days (int): Days digit: 1 - 31
hours (int): Hours digit: 0 - 23
minutes (int): Minutes digit: 0 - 59
seconds (int): Seconds digit: 0 - 59
Returns:
bool: True if successful
Raises:
CommandExecutionError: Raises an error if ``SetLocalTime`` function
fails
bool: ``True`` if successful, otherwise ``False``
CLI Example:
@ -1037,7 +1073,7 @@ def get_system_date():
Get the Windows system date
Returns:
str: The system date
str: Returns the system date
CLI Example:
@ -1054,7 +1090,8 @@ def set_system_date(newdate):
Set the Windows system date. Use <mm-dd-yy> format for the date.
Args:
newdate (str): The date to set. Can be any of the following formats:
newdate (str):
The date to set. Can be any of the following formats
- YYYY-MM-DD
- MM-DD-YYYY
@ -1063,6 +1100,9 @@ def set_system_date(newdate):
- MM/DD/YY
- YYYY/MM/DD
Returns:
bool: ``True`` if successful, otherwise ``False``
CLI Example:
.. code-block:: bash
@ -1087,7 +1127,7 @@ def start_time_service():
Start the Windows time service
Returns:
bool: True if successful, otherwise False.
bool: ``True`` if successful, otherwise ``False``
CLI Example:
@ -1103,7 +1143,7 @@ def stop_time_service():
Stop the Windows time service
Returns:
bool: True if successful, otherwise False
bool: ``True`` if successful, otherwise ``False``
CLI Example:
@ -1122,7 +1162,8 @@ def get_pending_component_servicing():
.. versionadded:: 2016.11.0
Returns:
bool: True if a reboot is pending, otherwise False.
bool: ``True`` if there are pending Component Based Servicing tasks,
otherwise ``False``
CLI Example:
@ -1146,12 +1187,14 @@ def get_pending_component_servicing():
def get_pending_domain_join():
'''
Determine whether there is a pending domain join action that requires a reboot.
Determine whether there is a pending domain join action that requires a
reboot.
.. versionadded:: 2016.11.0
Returns:
bool: True if a reboot is pending, otherwise False.
bool: ``True`` if there is a pending domain join action, otherwise
``False``
CLI Example:
@ -1193,7 +1236,8 @@ def get_pending_file_rename():
.. versionadded:: 2016.11.0
Returns:
bool: True if a reboot is pending, otherwise False.
bool: ``True`` if there are pending file rename operations, otherwise
``False``
CLI Example:
@ -1228,7 +1272,8 @@ def get_pending_servermanager():
.. versionadded:: 2016.11.0
Returns:
bool: True if a reboot is pending, otherwise False.
bool: ``True`` if there are pending Server Manager tasks, otherwise
``False``
CLI Example:
@ -1265,7 +1310,7 @@ def get_pending_update():
.. versionadded:: 2016.11.0
Returns:
bool: True if a reboot is pending, otherwise False.
bool: ``True`` if there are pending updates, otherwise ``False``
CLI Example:
@ -1305,14 +1350,14 @@ def set_reboot_required_witnessed():
current boot session. Also, in the scope of this key, the name *'Reboot
required'* will be assigned the value of *1*.
(For the time being, this this function is being used whenever an install
completes with exit code 3010 and this usage can be extended where
appropriate in the future.)
For the time being, this function is being used whenever an install
completes with exit code 3010 and can be extended where appropriate in the
future.
.. versionadded:: 2016.11.0
Returns:
bool: True if registry entry set successfuly, otherwise False.
bool: ``True`` if successful, otherwise ``False``
CLI Example:
@ -1330,16 +1375,18 @@ def set_reboot_required_witnessed():
def get_reboot_required_witnessed():
'''
This tells us if, at any time during the current boot session the salt
minion witnessed an event indicating that a reboot is required. (For the
time being, this function will return True if an install completed with exit
code 3010 during the current boot session and this usage can be extended
where appropriate in the future)
Determine if at any time during the current boot session the salt minion
witnessed an event indicating that a reboot is required.
This function will return ``True`` if an install completed with exit
code 3010 during the current boot session and can be extended where
appropriate in the future.
.. versionadded:: 2016.11.0
Returns:
bool: True if reboot required, otherwise False.
bool: ``True`` if the ``Requires reboot`` registry flag is set to ``1``,
otherwise ``False``
CLI Example:
@ -1361,7 +1408,7 @@ def get_pending_reboot():
.. versionadded:: 2016.11.0
Returns:
bool: True if pending reboot, otherwise False.
bool: ``True`` if the system is pending reboot, otherwise ``False``
CLI Example:

View file

@ -23,7 +23,14 @@ def output(ret, bar, **kwargs): # pylint: disable=unused-argument
Update the progress bar
'''
if 'return_count' in ret:
bar.update(ret['return_count'])
val = ret['return_count']
# Avoid to fail if targets are behind a syndic. In this case actual return count will be
# higher than targeted by MoM itself.
# TODO: implement a way to get the proper target minions count and remove this workaround.
# Details are in #44239.
if val > bar.maxval:
bar.maxval = val
bar.update(val)
return ''

View file

@ -71,6 +71,12 @@ def orchestrate(mods,
)
__opts__['file_client'] = 'local'
minion = salt.minion.MasterMinion(__opts__)
if pillarenv is None and 'pillarenv' in __opts__:
pillarenv = __opts__['pillarenv']
if saltenv is None and 'saltenv' in __opts__:
saltenv = __opts__['saltenv']
running = minion.functions['state.sls'](
mods,
test,

View file

@ -300,7 +300,7 @@ def present(name,
identifier
Custom-defined identifier for tracking the cron line for future crontab
edits. This defaults to the state id
edits. This defaults to the state name
special
A special keyword to specify periodicity (eg. @reboot, @hourly...).
@ -387,7 +387,7 @@ def absent(name,
identifier
Custom-defined identifier for tracking the cron line for future crontab
edits. This defaults to the state id
edits. This defaults to the state name
special
The special keyword used in the job (eg. @reboot, @hourly...).

View file

@ -2855,6 +2855,7 @@ def directory(name,
if __opts__['test']:
ret['result'] = presult
ret['comment'] = pcomment
ret['changes'] = ret['pchanges']
return ret
if not os.path.isdir(name):

View file

@ -1330,10 +1330,14 @@ def fopen(*args, **kwargs):
if len(args) > 1:
args = list(args)
if 'b' not in args[1]:
args[1] += 'b'
elif kwargs.get('mode', None):
args[1] = args[1].replace('t', 'b')
if 'b' not in args[1]:
args[1] += 'b'
elif kwargs.get('mode'):
if 'b' not in kwargs['mode']:
kwargs['mode'] += 'b'
kwargs['mode'] = kwargs['mode'].replace('t', 'b')
if 'b' not in kwargs['mode']:
kwargs['mode'] += 'b'
else:
# the default is to read
kwargs['mode'] = 'rb'

View file

@ -44,7 +44,9 @@ def guess_archive_type(name):
Guess an archive type (tar, zip, or rar) by its file extension
'''
name = name.lower()
for ending in ('tar', 'tar.gz', 'tar.bz2', 'tar.xz', 'tgz', 'tbz2', 'txz',
for ending in ('tar', 'tar.gz', 'tgz',
'tar.bz2', 'tbz2', 'tbz',
'tar.xz', 'txz',
'tar.lzma', 'tlz'):
if name.endswith('.' + ending):
return 'tar'

View file

@ -439,7 +439,7 @@ class GitProvider(object):
return root_dir
log.error(
'Root path \'%s\' not present in %s remote \'%s\', '
'skipping.', self.root, self.role, self.id
'skipping.', self.root(), self.role, self.id
)
return None

View file

@ -800,7 +800,10 @@ class TestDaemon(object):
# Set up config options that require internal data
master_opts['pillar_roots'] = syndic_master_opts['pillar_roots'] = {
'base': [os.path.join(FILES, 'pillar', 'base')]
'base': [
RUNTIME_VARS.TMP_PILLAR_TREE,
os.path.join(FILES, 'pillar', 'base'),
]
}
master_opts['file_roots'] = syndic_master_opts['file_roots'] = {
'base': [
@ -976,6 +979,7 @@ class TestDaemon(object):
sub_minion_opts['sock_dir'],
minion_opts['sock_dir'],
RUNTIME_VARS.TMP_STATE_TREE,
RUNTIME_VARS.TMP_PILLAR_TREE,
RUNTIME_VARS.TMP_PRODENV_STATE_TREE,
TMP,
],
@ -1087,7 +1091,8 @@ class TestDaemon(object):
os.chmod(path, stat.S_IRWXU)
func(path)
for dirname in (TMP, RUNTIME_VARS.TMP_STATE_TREE, RUNTIME_VARS.TMP_PRODENV_STATE_TREE):
for dirname in (TMP, RUNTIME_VARS.TMP_STATE_TREE,
RUNTIME_VARS.TMP_PILLAR_TREE, RUNTIME_VARS.TMP_PRODENV_STATE_TREE):
if os.path.isdir(dirname):
shutil.rmtree(dirname, onerror=remove_readonly)

View file

@ -5,10 +5,16 @@ Integration tests for the saltutil module.
# Import Python libs
from __future__ import absolute_import
import os
import time
import textwrap
# Import Salt Testing libs
from tests.support.case import ModuleCase
from tests.support.paths import TMP_PILLAR_TREE
# Import Salt Libs
import salt.utils
class SaltUtilModuleTest(ModuleCase):
@ -153,3 +159,38 @@ class SaltUtilSyncModuleTest(ModuleCase):
ret = self.run_function('saltutil.sync_all', extmod_whitelist={'modules': ['runtests_decorators']},
extmod_blacklist={'modules': ['runtests_decorators']})
self.assertEqual(ret, expected_return)
class SaltUtilSyncPillarTest(ModuleCase):
'''
Testcase for the saltutil sync pillar module
'''
def test_pillar_refresh(self):
'''
test pillar refresh module
'''
pillar_key = 'itworked'
pre_pillar = self.run_function('pillar.raw')
self.assertNotIn(pillar_key, pre_pillar.get(pillar_key, 'didnotwork'))
with salt.utils.fopen(os.path.join(TMP_PILLAR_TREE, 'add_pillar.sls'), 'w') as fp:
fp.write('{0}: itworked'.format(pillar_key))
with salt.utils.fopen(os.path.join(TMP_PILLAR_TREE, 'top.sls'), 'w') as fp:
fp.write(textwrap.dedent('''\
base:
'*':
- add_pillar
'''))
pillar_refresh = self.run_function('saltutil.refresh_pillar')
wait = self.run_function('test.sleep', [1])
post_pillar = self.run_function('pillar.raw')
self.assertIn(pillar_key, post_pillar.get(pillar_key, 'didnotwork'))
def tearDown(self):
for filename in os.listdir(TMP_PILLAR_TREE):
os.remove(os.path.join(TMP_PILLAR_TREE, filename))

View file

@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
# Import python libs
from __future__ import absolute_import
# Import Salt Testing libs
from tests.support.case import ModuleCase
from tests.support.helpers import destructiveTest
# Import Salt libs
import salt.utils
@destructiveTest
class ServiceModuleTest(ModuleCase):
'''
Module testing the service module
'''
def setUp(self):
self.service_name = 'cron'
cmd_name = 'crontab'
os_family = self.run_function('grains.get', ['os_family'])
if os_family == 'RedHat':
self.service_name = 'crond'
elif os_family == 'Arch':
self.service_name = 'systemd-journald'
cmd_name = 'systemctl'
if salt.utils.which(cmd_name) is None:
self.skipTest('{0} is not installed'.format(cmd_name))
def test_service_status_running(self):
'''
test service.status execution module
when service is running
'''
start_service = self.run_function('service.start', [self.service_name])
check_service = self.run_function('service.status', [self.service_name])
self.assertTrue(check_service)
def test_service_status_dead(self):
'''
test service.status execution module
when service is dead
'''
stop_service = self.run_function('service.stop', [self.service_name])
check_service = self.run_function('service.status', [self.service_name])
self.assertFalse(check_service)

View file

@ -7,13 +7,17 @@ from __future__ import absolute_import
import os
import shutil
# Import Salt libs
import salt.utils
# Import Salt Testing libs
from tests.support.case import SPMCase
from tests.support.case import SPMCase, ModuleCase
from tests.support.helpers import destructiveTest
from tests.support.unit import skipIf
@destructiveTest
class SPMBuildTest(SPMCase):
class SPMBuildTest(SPMCase, ModuleCase):
'''
Validate the spm build command
'''
@ -32,5 +36,50 @@ class SPMBuildTest(SPMCase):
# Make sure formula path dir is created
self.assertTrue(os.path.isdir(self.config['formula_path']))
@skipIf(salt.utils.which('fallocate') is None, 'fallocate not installed')
def test_spm_build_big_file(self):
'''
test spm build with a big file
'''
# check to make sure there is enough space to run this test
check_space = self.run_function('status.diskusage', ['/'])
space = check_space['/']['available']
if space < 2000000:
self.skipTest('Not enough space on host to run this test')
big_file = self.run_function('cmd.run',
['fallocate -l 1G {0}'.format(os.path.join(self.formula_sls_dir,
'bigfile.txt'))])
build_spm = self.run_spm('build', self.config, self.formula_dir)
spm_file = os.path.join(self.config['spm_build_dir'], 'apache-201506-2.spm')
install = self.run_spm('install', self.config, spm_file)
get_files = self.run_spm('files', self.config, 'apache')
files = ['apache.sls', 'bigfile.txt']
for sls in files:
self.assertIn(sls, ' '.join(get_files))
def test_spm_build_exclude(self):
'''
test spm build while excluding directory
'''
git_dir = os.path.join(self.formula_sls_dir, '.git')
os.makedirs(git_dir)
files = ['donotbuild1', 'donotbuild2', 'donotbuild3']
for git_file in files:
with salt.utils.fopen(os.path.join(git_dir, git_file), 'w') as fp:
fp.write('Please do not include me in build')
build_spm = self.run_spm('build', self.config, self.formula_dir)
spm_file = os.path.join(self.config['spm_build_dir'], 'apache-201506-2.spm')
install = self.run_spm('install', self.config, spm_file)
get_files = self.run_spm('files', self.config, 'apache')
for git_file in files:
self.assertNotIn(git_file, ' '.join(get_files))
def tearDown(self):
shutil.rmtree(self._tmp_spm)

View file

@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
'''
Tests for the spm remove utility
'''
# Import python libs
from __future__ import absolute_import
import os
import shutil
# Import Salt Testing libs
from tests.support.case import SPMCase
from tests.support.helpers import destructiveTest
@destructiveTest
class SPMRemoveTest(SPMCase):
'''
Validate the spm remove command
'''
def setUp(self):
self.config = self._spm_config()
self._spm_build_files(self.config)
def test_spm_remove(self):
'''
test spm remove from an inital repo install
'''
# first install apache package
self._spm_create_update_repo(self.config)
install = self.run_spm('install', self.config, 'apache')
sls = os.path.join(self.config['formula_path'], 'apache', 'apache.sls')
self.assertTrue(os.path.exists(sls))
#now remove an make sure file is removed
remove = self.run_spm('remove', self.config, 'apache')
sls = os.path.join(self.config['formula_path'], 'apache', 'apache.sls')
self.assertFalse(os.path.exists(sls))
self.assertIn('... removing apache', remove)
def tearDown(self):
shutil.rmtree(self._tmp_spm)

View file

@ -626,7 +626,7 @@ class SPMCase(TestCase, AdaptedConfigurationTestCaseMixin):
'spm_repos_config': os.path.join(self._tmp_spm, 'etc', 'spm.repos'),
'spm_cache_dir': os.path.join(self._tmp_spm, 'cache'),
'spm_build_dir': os.path.join(self._tmp_spm, 'build'),
'spm_build_exclude': ['.git'],
'spm_build_exclude': ['apache/.git'],
'spm_db_provider': 'sqlite3',
'spm_files_provider': 'local',
'spm_db': os.path.join(self._tmp_spm, 'packages.db'),

View file

@ -0,0 +1,68 @@
# -*- coding: utf-8 -*-
'''
Script for copying back xml junit files from tests
'''
from __future__ import absolute_import, print_function
import argparse # pylint: disable=minimum-python-version
import os
import paramiko
import subprocess
import yaml
class DownloadArtifacts(object):
def __init__(self, instance, artifacts):
self.instance = instance
self.artifacts = artifacts
self.client = self.setup_transport()
def setup_transport(self):
# pylint: disable=minimum-python-version
config = yaml.load(subprocess.check_output(['bundle', 'exec', 'kitchen', 'diagnose', self.instance]))
# pylint: enable=minimum-python-version
state = config['instances'][self.instance]['state_file']
tport = config['instances'][self.instance]['transport']
transport = paramiko.Transport((
state['hostname'],
state.get('port', tport.get('port', 22))
))
pkey = paramiko.rsakey.RSAKey(
filename=state.get('ssh_key', tport.get('ssh_key', '~/.ssh/id_rsa'))
)
transport.connect(
username=state.get('username', tport.get('username', 'root')),
pkey=pkey
)
return paramiko.SFTPClient.from_transport(transport)
def download(self):
for remote, local in self.artifacts:
if remote.endswith('/'):
for fxml in self.client.listdir(remote):
self._do_download(os.path.join(remote, fxml), os.path.join(local, os.path.basename(fxml)))
else:
self._do_download(remote, os.path.join(local, os.path.basename(remote)))
def _do_download(self, remote, local):
print('Copying from {0} to {1}'.format(remote, local))
self.client.get(remote, local)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Jenkins Artifact Download Helper')
parser.add_argument(
'--instance',
required=True,
action='store',
help='Instance on Test Kitchen to pull from',
)
parser.add_argument(
'--download-artifacts',
dest='artifacts',
nargs=2,
action='append',
metavar=('REMOTE_PATH', 'LOCAL_PATH'),
help='Download remote artifacts',
)
args = parser.parse_args()
downloader = DownloadArtifacts(args.instance, args.artifacts)
downloader.download()

View file

@ -52,6 +52,7 @@ PYEXEC = 'python{0}.{1}'.format(*sys.version_info)
MOCKBIN = os.path.join(INTEGRATION_TEST_DIR, 'mockbin')
SCRIPT_DIR = os.path.join(CODE_DIR, 'scripts')
TMP_STATE_TREE = os.path.join(SYS_TMP_DIR, 'salt-temp-state-tree')
TMP_PILLAR_TREE = os.path.join(SYS_TMP_DIR, 'salt-temp-pillar-tree')
TMP_PRODENV_STATE_TREE = os.path.join(SYS_TMP_DIR, 'salt-temp-prodenv-state-tree')
TMP_CONF_DIR = os.path.join(TMP, 'config')
TMP_SUB_MINION_CONF_DIR = os.path.join(TMP_CONF_DIR, 'sub-minion')

View file

@ -215,6 +215,7 @@ RUNTIME_VARS = RuntimeVars(
TMP_SYNDIC_MINION_CONF_DIR=paths.TMP_SYNDIC_MINION_CONF_DIR,
TMP_SCRIPT_DIR=paths.TMP_SCRIPT_DIR,
TMP_STATE_TREE=paths.TMP_STATE_TREE,
TMP_PILLAR_TREE=paths.TMP_PILLAR_TREE,
TMP_PRODENV_STATE_TREE=paths.TMP_PRODENV_STATE_TREE,
RUNNING_TESTS_USER=RUNNING_TESTS_USER,
RUNTIME_CONFIGS={}

View file

@ -814,7 +814,8 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
ret.update({
'comment': comt,
'result': None,
'pchanges': p_chg
'pchanges': p_chg,
'changes': {'/etc/grub.conf': {'directory': 'new'}}
})
self.assertDictEqual(filestate.directory(name,
user=user,
@ -825,7 +826,7 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
with patch.object(os.path, 'isdir', mock_f):
comt = ('No directory to create {0} in'
.format(name))
ret.update({'comment': comt, 'result': False})
ret.update({'comment': comt, 'result': False, 'changes': {}})
self.assertDictEqual(filestate.directory
(name, user=user, group=group),
ret)

View file

@ -313,21 +313,21 @@ class PyDSLRendererTestCase(CommonTestCaseBoilerplate):
- cwd: /
.Y:
cmd.run:
- name: echo Y >> {1}
- name: echo Y >> {0}
- cwd: /
.Z:
cmd.run:
- name: echo Z >> {2}
- name: echo Z >> {0}
- cwd: /
'''.format(output, output, output)))
'''.format(output.replace('\\', '/'))))
write_to(os.path.join(dirpath, 'yyy.sls'), textwrap.dedent('''\
#!pydsl|stateconf -ps
__pydsl__.set(ordered=True)
state('.D').cmd.run('echo D >> {0}', cwd='/')
state('.E').cmd.run('echo E >> {1}', cwd='/')
state('.F').cmd.run('echo F >> {2}', cwd='/')
'''.format(output, output, output)))
state('.E').cmd.run('echo E >> {0}', cwd='/')
state('.F').cmd.run('echo F >> {0}', cwd='/')
'''.format(output.replace('\\', '/'))))
write_to(os.path.join(dirpath, 'aaa.sls'), textwrap.dedent('''\
#!pydsl|stateconf -ps
@ -343,9 +343,9 @@ class PyDSLRendererTestCase(CommonTestCaseBoilerplate):
__pydsl__.set(ordered=True)
state('.A').cmd.run('echo A >> {0}', cwd='/')
state('.B').cmd.run('echo B >> {1}', cwd='/')
state('.C').cmd.run('echo C >> {2}', cwd='/')
'''.format(output, output, output)))
state('.B').cmd.run('echo B >> {0}', cwd='/')
state('.C').cmd.run('echo C >> {0}', cwd='/')
'''.format(output.replace('\\', '/'))))
self.state_highstate({'base': ['aaa']}, dirpath)
with salt.utils.fopen(output, 'r') as f:
@ -365,26 +365,29 @@ class PyDSLRendererTestCase(CommonTestCaseBoilerplate):
)
)
try:
# The Windows shell will include any spaces before the redirect
# in the text that is redirected.
# For example: echo hello > test.txt will contain "hello "
write_to(os.path.join(dirpath, 'aaa.sls'), textwrap.dedent('''\
#!pydsl
__pydsl__.set(ordered=True)
A = state('A')
A.cmd.run('echo hehe > {0}/zzz.txt', cwd='/')
A.file.managed('{1}/yyy.txt', source='salt://zzz.txt')
A.cmd.run('echo hehe>{0}/zzz.txt', cwd='/')
A.file.managed('{0}/yyy.txt', source='salt://zzz.txt')
A()
A()
state().cmd.run('echo hoho >> {2}/yyy.txt', cwd='/')
state().cmd.run('echo hoho>>{0}/yyy.txt', cwd='/')
A.file.managed('{3}/xxx.txt', source='salt://zzz.txt')
A.file.managed('{0}/xxx.txt', source='salt://zzz.txt')
A()
'''.format(dirpath, dirpath, dirpath, dirpath)))
'''.format(dirpath.replace('\\', '/'))))
self.state_highstate({'base': ['aaa']}, dirpath)
with salt.utils.fopen(os.path.join(dirpath, 'yyy.txt'), 'rt') as f:
self.assertEqual(f.read(), 'hehe\nhoho\n')
self.assertEqual(f.read(), 'hehe' + os.linesep + 'hoho' + os.linesep)
with salt.utils.fopen(os.path.join(dirpath, 'xxx.txt'), 'rt') as f:
self.assertEqual(f.read(), 'hehe\n')
self.assertEqual(f.read(), 'hehe' + os.linesep)
finally:
shutil.rmtree(dirpath, ignore_errors=True)