003 File Manager
Current Path:
/usr/local/lib/python3.8/site-packages/salt/modules
usr
/
local
/
lib
/
python3.8
/
site-packages
/
salt
/
modules
/
📁
..
📄
__init__.py
(35 B)
📁
__pycache__
📄
acme.py
(12.74 KB)
📄
aix_group.py
(4.11 KB)
📄
aix_shadow.py
(1.93 KB)
📄
aixpkg.py
(10.91 KB)
📄
aliases.py
(5.07 KB)
📄
alternatives.py
(5.1 KB)
📄
ansiblegate.py
(11.38 KB)
📄
apache.py
(12.47 KB)
📄
apcups.py
(2.21 KB)
📄
apf.py
(3.09 KB)
📄
apkpkg.py
(16 KB)
📄
aptly.py
(15.28 KB)
📄
aptpkg.py
(102.35 KB)
📄
archive.py
(46.97 KB)
📄
arista_pyeapi.py
(22.06 KB)
📄
artifactory.py
(24.78 KB)
📄
at.py
(10.65 KB)
📄
at_solaris.py
(8.56 KB)
📄
augeas_cfg.py
(13.93 KB)
📄
aws_sqs.py
(6.55 KB)
📄
azurearm_compute.py
(19.55 KB)
📄
azurearm_dns.py
(14.7 KB)
📄
azurearm_network.py
(80.8 KB)
📄
azurearm_resource.py
(34.27 KB)
📄
bamboohr.py
(7.36 KB)
📄
baredoc.py
(11.13 KB)
📄
bcache.py
(28.97 KB)
📄
beacons.py
(27.89 KB)
📄
bigip.py
(69.11 KB)
📄
bluez_bluetooth.py
(6.76 KB)
📄
boto3_elasticache.py
(37.34 KB)
📄
boto3_elasticsearch.py
(53.17 KB)
📄
boto3_route53.py
(39.75 KB)
📄
boto3_sns.py
(12.93 KB)
📄
boto_apigateway.py
(61.86 KB)
📄
boto_asg.py
(35.7 KB)
📄
boto_cfn.py
(7.95 KB)
📄
boto_cloudfront.py
(12.75 KB)
📄
boto_cloudtrail.py
(14.45 KB)
📄
boto_cloudwatch.py
(10.99 KB)
📄
boto_cloudwatch_event.py
(9.48 KB)
📄
boto_cognitoidentity.py
(14.63 KB)
📄
boto_datapipeline.py
(6.94 KB)
📄
boto_dynamodb.py
(10.54 KB)
📄
boto_ec2.py
(79.29 KB)
📄
boto_efs.py
(14.05 KB)
📄
boto_elasticache.py
(23.69 KB)
📄
boto_elasticsearch_domain.py
(15.85 KB)
📄
boto_elb.py
(35.4 KB)
📄
boto_elbv2.py
(10.81 KB)
📄
boto_iam.py
(75.62 KB)
📄
boto_iot.py
(26.2 KB)
📄
boto_kinesis.py
(19.63 KB)
📄
boto_kms.py
(17.29 KB)
📄
boto_lambda.py
(35.05 KB)
📄
boto_rds.py
(34.92 KB)
📄
boto_route53.py
(32.55 KB)
📄
boto_s3.py
(4.24 KB)
📄
boto_s3_bucket.py
(31.8 KB)
📄
boto_secgroup.py
(25.22 KB)
📄
boto_sns.py
(7.22 KB)
📄
boto_sqs.py
(6.43 KB)
📄
boto_ssm.py
(3.65 KB)
📄
boto_vpc.py
(112.81 KB)
📄
bower.py
(5.89 KB)
📄
bridge.py
(10.86 KB)
📄
bsd_shadow.py
(6.92 KB)
📄
btrfs.py
(33.64 KB)
📄
cabal.py
(3.79 KB)
📄
capirca_acl.py
(40.04 KB)
📄
cassandra_cql.py
(39 KB)
📄
cassandra_mod.py
(3.97 KB)
📄
celery.py
(3.33 KB)
📄
ceph.py
(15.82 KB)
📄
chassis.py
(1.52 KB)
📄
chef.py
(4.66 KB)
📄
chocolatey.py
(39.34 KB)
📄
chronos.py
(2.89 KB)
📄
chroot.py
(11.51 KB)
📄
cimc.py
(23.02 KB)
📄
ciscoconfparse_mod.py
(14.79 KB)
📄
cisconso.py
(3.83 KB)
📄
cloud.py
(9.39 KB)
📄
cmdmod.py
(162.16 KB)
📄
composer.py
(10.31 KB)
📄
config.py
(16.85 KB)
📄
consul.py
(68.93 KB)
📄
container_resource.py
(13.36 KB)
📄
cp.py
(27.98 KB)
📄
cpan.py
(5.54 KB)
📄
cron.py
(26.8 KB)
📄
cryptdev.py
(10.08 KB)
📄
csf.py
(16.04 KB)
📄
cyg.py
(8.32 KB)
📄
daemontools.py
(5.41 KB)
📄
data.py
(3.83 KB)
📄
datadog_api.py
(7.64 KB)
📄
ddns.py
(7.04 KB)
📄
deb_apache.py
(7.41 KB)
📄
deb_postgres.py
(4.22 KB)
📄
debconfmod.py
(4.06 KB)
📄
debian_ip.py
(64.78 KB)
📄
debian_service.py
(6.6 KB)
📄
debuild_pkgbuild.py
(34.69 KB)
📄
defaults.py
(5.42 KB)
📄
devinfo.py
(9.05 KB)
📄
devmap.py
(627 B)
📄
dig.py
(7.45 KB)
📄
disk.py
(30.44 KB)
📄
djangomod.py
(7.53 KB)
📄
dnsmasq.py
(5.71 KB)
📄
dnsutil.py
(11.51 KB)
📄
dockercompose.py
(32.62 KB)
📄
dockermod.py
(224.97 KB)
📄
dpkg_lowpkg.py
(12.9 KB)
📄
drac.py
(10.97 KB)
📄
dracr.py
(38.53 KB)
📄
drbd.py
(7.19 KB)
📄
dummyproxy_pkg.py
(2.46 KB)
📄
dummyproxy_service.py
(2.91 KB)
📄
ebuildpkg.py
(38.74 KB)
📄
eix.py
(1.58 KB)
📄
elasticsearch.py
(51.44 KB)
📄
environ.py
(8.96 KB)
📄
eselect.py
(4.99 KB)
📄
esxcluster.py
(502 B)
📄
esxdatacenter.py
(514 B)
📄
esxi.py
(1.64 KB)
📄
esxvm.py
(481 B)
📄
etcd_mod.py
(7.02 KB)
📄
ethtool.py
(7.65 KB)
📄
event.py
(8.23 KB)
📄
extfs.py
(8.78 KB)
📄
file.py
(224.74 KB)
📄
firewalld.py
(20.51 KB)
📄
freebsd_sysctl.py
(4.76 KB)
📄
freebsd_update.py
(6.19 KB)
📄
freebsdjail.py
(7.16 KB)
📄
freebsdkmod.py
(6.17 KB)
📄
freebsdpkg.py
(17.04 KB)
📄
freebsdports.py
(13.13 KB)
📄
freebsdservice.py
(12.53 KB)
📄
freezer.py
(8.91 KB)
📄
gcp_addon.py
(4.07 KB)
📄
gem.py
(10.6 KB)
📄
genesis.py
(21.75 KB)
📄
gentoo_service.py
(9.18 KB)
📄
gentoolkitmod.py
(8.33 KB)
📄
git.py
(171.44 KB)
📄
github.py
(53.19 KB)
📄
glanceng.py
(4.69 KB)
📄
glassfish.py
(19.49 KB)
📄
glusterfs.py
(19.55 KB)
📄
gnomedesktop.py
(6.85 KB)
📄
google_chat.py
(1.52 KB)
📄
gpg.py
(39.99 KB)
📄
grafana4.py
(30.27 KB)
📄
grains.py
(23.67 KB)
📄
groupadd.py
(10.85 KB)
📄
grub_legacy.py
(3.08 KB)
📄
guestfs.py
(2.32 KB)
📄
hadoop.py
(3.76 KB)
📄
haproxyconn.py
(10.17 KB)
📄
hashutil.py
(6.77 KB)
📄
heat.py
(25.26 KB)
📄
helm.py
(39.27 KB)
📄
hg.py
(7.16 KB)
📄
highstate_doc.py
(22.76 KB)
📄
hosts.py
(10.47 KB)
📄
http.py
(3.75 KB)
📄
icinga2.py
(4.46 KB)
📄
idem.py
(1.75 KB)
📄
ifttt.py
(2.28 KB)
📄
ilo.py
(15.98 KB)
📄
incron.py
(7.68 KB)
📄
influxdb08mod.py
(15.07 KB)
📄
influxdbmod.py
(16.13 KB)
📄
infoblox.py
(17.53 KB)
📄
ini_manage.py
(14.63 KB)
📁
inspectlib
📄
inspector.py
(8.19 KB)
📄
introspect.py
(4.02 KB)
📄
iosconfig.py
(14.78 KB)
📄
ipmi.py
(25.45 KB)
📄
ipset.py
(17.97 KB)
📄
iptables.py
(57.33 KB)
📄
iwtools.py
(3.99 KB)
📄
jboss7.py
(20.51 KB)
📄
jboss7_cli.py
(15.23 KB)
📄
jenkinsmod.py
(11.9 KB)
📄
jinja.py
(2.66 KB)
📄
jira_mod.py
(7.07 KB)
📄
junos.py
(73.9 KB)
📄
k8s.py
(24.87 KB)
📄
kapacitor.py
(5.37 KB)
📄
kerberos.py
(5.42 KB)
📄
kernelpkg_linux_apt.py
(6.91 KB)
📄
kernelpkg_linux_yum.py
(7.46 KB)
📄
key.py
(1007 B)
📄
keyboard.py
(2.64 KB)
📄
keystone.py
(43.16 KB)
📄
keystoneng.py
(21.82 KB)
📄
keystore.py
(6.69 KB)
📄
kmod.py
(7.29 KB)
📄
kubeadm.py
(34.01 KB)
📄
kubernetesmod.py
(46.66 KB)
📄
launchctl_service.py
(9.73 KB)
📄
layman.py
(4.22 KB)
📄
ldap3.py
(18.81 KB)
📄
ldapmod.py
(5.9 KB)
📄
libcloud_compute.py
(23.51 KB)
📄
libcloud_dns.py
(9.76 KB)
📄
libcloud_loadbalancer.py
(13.17 KB)
📄
libcloud_storage.py
(12.19 KB)
📄
linux_acl.py
(7.7 KB)
📄
linux_ip.py
(5.44 KB)
📄
linux_lvm.py
(17.86 KB)
📄
linux_service.py
(4.64 KB)
📄
linux_shadow.py
(13.37 KB)
📄
linux_sysctl.py
(7.39 KB)
📄
localemod.py
(11.84 KB)
📄
locate.py
(2.58 KB)
📄
logadm.py
(9.57 KB)
📄
logmod.py
(1.24 KB)
📄
logrotate.py
(7.72 KB)
📄
lvs.py
(11.54 KB)
📄
lxc.py
(148.61 KB)
📄
lxd.py
(90.2 KB)
📄
mac_assistive.py
(6.36 KB)
📄
mac_brew_pkg.py
(19.82 KB)
📄
mac_desktop.py
(2.77 KB)
📄
mac_group.py
(6.34 KB)
📄
mac_keychain.py
(6.68 KB)
📄
mac_pkgutil.py
(2.84 KB)
📄
mac_portspkg.py
(11.36 KB)
📄
mac_power.py
(13.29 KB)
📄
mac_service.py
(19.64 KB)
📄
mac_shadow.py
(14.23 KB)
📄
mac_softwareupdate.py
(14.52 KB)
📄
mac_sysctl.py
(5.13 KB)
📄
mac_system.py
(15.2 KB)
📄
mac_timezone.py
(8.34 KB)
📄
mac_user.py
(16.36 KB)
📄
mac_xattr.py
(6.11 KB)
📄
macdefaults.py
(2.33 KB)
📄
macpackage.py
(6.94 KB)
📄
makeconf.py
(17.31 KB)
📄
mandrill.py
(6.31 KB)
📄
marathon.py
(5.36 KB)
📄
match.py
(10.28 KB)
📄
mattermost.py
(3.4 KB)
📄
mdadm_raid.py
(9.86 KB)
📄
mdata.py
(3.44 KB)
📄
memcached.py
(6.13 KB)
📄
mine.py
(18.79 KB)
📄
minion.py
(7.68 KB)
📄
mod_random.py
(6.72 KB)
📄
modjk.py
(12.48 KB)
📄
mongodb.py
(17.3 KB)
📄
monit.py
(5.51 KB)
📄
moosefs.py
(3.87 KB)
📄
mount.py
(56.18 KB)
📄
mssql.py
(14.64 KB)
📄
msteams.py
(2 KB)
📄
munin.py
(2.4 KB)
📄
mysql.py
(87.86 KB)
📄
nacl.py
(9.73 KB)
📄
nagios.py
(6.53 KB)
📄
nagios_rpc.py
(5.09 KB)
📄
namecheap_domains.py
(12.84 KB)
📄
namecheap_domains_dns.py
(5.93 KB)
📄
namecheap_domains_ns.py
(4.51 KB)
📄
namecheap_ssl.py
(25.72 KB)
📄
namecheap_users.py
(2.4 KB)
📄
napalm_bgp.py
(9.72 KB)
📄
napalm_formula.py
(11.33 KB)
📄
napalm_mod.py
(59.3 KB)
📄
napalm_netacl.py
(28.59 KB)
📄
napalm_network.py
(93.24 KB)
📄
napalm_ntp.py
(10.22 KB)
📄
napalm_probes.py
(13.25 KB)
📄
napalm_route.py
(5.09 KB)
📄
napalm_snmp.py
(7.05 KB)
📄
napalm_users.py
(6.49 KB)
📄
napalm_yang_mod.py
(20.28 KB)
📄
netaddress.py
(1.6 KB)
📄
netbox.py
(32.22 KB)
📄
netbsd_sysctl.py
(3.97 KB)
📄
netbsdservice.py
(6.49 KB)
📄
netmiko_mod.py
(19.63 KB)
📄
netscaler.py
(27.02 KB)
📄
network.py
(62.75 KB)
📄
neutron.py
(44.93 KB)
📄
neutronng.py
(15.02 KB)
📄
nexus.py
(22.95 KB)
📄
nfs3.py
(3.9 KB)
📄
nftables.py
(33.58 KB)
📄
nginx.py
(3.83 KB)
📄
nilrt_ip.py
(36.18 KB)
📄
nix.py
(8.03 KB)
📄
nova.py
(19.61 KB)
📄
npm.py
(10.35 KB)
📄
nspawn.py
(41.35 KB)
📄
nxos.py
(24.67 KB)
📄
nxos_api.py
(14.66 KB)
📄
nxos_upgrade.py
(14.74 KB)
📄
omapi.py
(3.6 KB)
📄
openbsd_sysctl.py
(3.74 KB)
📄
openbsdpkg.py
(11 KB)
📄
openbsdrcctl_service.py
(6.25 KB)
📄
openbsdservice.py
(8.31 KB)
📄
openscap.py
(2.81 KB)
📄
openstack_config.py
(3.5 KB)
📄
openstack_mng.py
(2.71 KB)
📄
openvswitch.py
(11.75 KB)
📄
opkg.py
(49.72 KB)
📄
opsgenie.py
(3.29 KB)
📄
oracle.py
(5.83 KB)
📄
osquery.py
(24.93 KB)
📄
out.py
(2.53 KB)
📄
pacmanpkg.py
(31.99 KB)
📄
pagerduty.py
(4.7 KB)
📄
pagerduty_util.py
(13.49 KB)
📄
pam.py
(2.01 KB)
📄
panos.py
(61.05 KB)
📄
parallels.py
(19.85 KB)
📄
parted_partition.py
(21.53 KB)
📄
pcs.py
(14.11 KB)
📄
pdbedit.py
(10.72 KB)
📄
pecl.py
(3.79 KB)
📄
peeringdb.py
(8.39 KB)
📄
pf.py
(9.51 KB)
📄
philips_hue.py
(1.55 KB)
📄
pillar.py
(21.29 KB)
📄
pip.py
(51.76 KB)
📄
pkg_resource.py
(11.89 KB)
📄
pkgin.py
(17.35 KB)
📄
pkgng.py
(61.1 KB)
📄
pkgutil.py
(9.88 KB)
📄
portage_config.py
(22.77 KB)
📄
postfix.py
(16.24 KB)
📄
postgres.py
(88.31 KB)
📄
poudriere.py
(7.85 KB)
📄
powerpath.py
(2.57 KB)
📄
proxy.py
(11.49 KB)
📄
ps.py
(19.45 KB)
📄
publish.py
(10.22 KB)
📄
puppet.py
(11.69 KB)
📄
purefa.py
(33.03 KB)
📄
purefb.py
(13.65 KB)
📄
pushbullet.py
(1.88 KB)
📄
pushover_notify.py
(3.48 KB)
📄
pw_group.py
(4.4 KB)
📄
pw_user.py
(12.47 KB)
📄
pyenv.py
(6.93 KB)
📄
qemu_img.py
(1.53 KB)
📄
qemu_nbd.py
(3.28 KB)
📄
quota.py
(6.43 KB)
📄
rabbitmq.py
(38.44 KB)
📄
rallydev.py
(6.09 KB)
📄
random_org.py
(23.76 KB)
📄
rbac_solaris.py
(16.15 KB)
📄
rbenv.py
(10.75 KB)
📄
rdp.py
(6.08 KB)
📄
rebootmgr.py
(7.66 KB)
📄
redismod.py
(16.36 KB)
📄
reg.py
(16.36 KB)
📄
rest_pkg.py
(2.26 KB)
📄
rest_sample_utils.py
(558 B)
📄
rest_service.py
(3.63 KB)
📄
restartcheck.py
(24.1 KB)
📄
ret.py
(1.27 KB)
📄
rh_ip.py
(38.01 KB)
📄
rh_service.py
(16.61 KB)
📄
riak.py
(5.19 KB)
📄
rpm_lowpkg.py
(27.61 KB)
📄
rpmbuild_pkgbuild.py
(24.53 KB)
📄
rsync.py
(8.04 KB)
📄
runit.py
(17.14 KB)
📄
rvm.py
(11.1 KB)
📄
s3.py
(9.93 KB)
📄
s6.py
(3.62 KB)
📄
salt_proxy.py
(4.48 KB)
📄
salt_version.py
(4.29 KB)
📄
saltcheck.py
(46.11 KB)
📄
saltcloudmod.py
(954 B)
📄
saltutil.py
(56.5 KB)
📄
schedule.py
(43.35 KB)
📄
scp_mod.py
(6.22 KB)
📄
scsi.py
(2.66 KB)
📄
sdb.py
(2.45 KB)
📄
seed.py
(8.87 KB)
📄
selinux.py
(23.83 KB)
📄
sensehat.py
(7.79 KB)
📄
sensors.py
(1.3 KB)
📄
serverdensity_device.py
(8.1 KB)
📄
servicenow.py
(4.38 KB)
📄
slack_notify.py
(7.83 KB)
📄
slackware_service.py
(6.89 KB)
📄
slsutil.py
(19.05 KB)
📄
smartos_imgadm.py
(12.09 KB)
📄
smartos_nictagadm.py
(6.51 KB)
📄
smartos_virt.py
(5.21 KB)
📄
smartos_vmadm.py
(26.37 KB)
📄
smbios.py
(10.06 KB)
📄
smf_service.py
(8.52 KB)
📄
smtp.py
(5.41 KB)
📄
snapper.py
(27.14 KB)
📄
solaris_fmadm.py
(11.27 KB)
📄
solaris_group.py
(2.8 KB)
📄
solaris_shadow.py
(7.98 KB)
📄
solaris_system.py
(3.72 KB)
📄
solaris_user.py
(11.06 KB)
📄
solarisipspkg.py
(18.7 KB)
📄
solarispkg.py
(15.42 KB)
📄
solr.py
(45.54 KB)
📄
solrcloud.py
(14.63 KB)
📄
splunk.py
(8.15 KB)
📄
splunk_search.py
(8.76 KB)
📄
sqlite3.py
(2.54 KB)
📄
ssh.py
(43.15 KB)
📄
ssh_pkg.py
(1.08 KB)
📄
ssh_service.py
(3.39 KB)
📄
state.py
(78.55 KB)
📄
status.py
(57.34 KB)
📄
statuspage.py
(14.67 KB)
📄
supervisord.py
(11.15 KB)
📄
suse_apache.py
(2.45 KB)
📄
svn.py
(10.75 KB)
📄
swarm.py
(13.5 KB)
📄
swift.py
(5.55 KB)
📄
sysbench.py
(6.62 KB)
📄
sysfs.py
(6.61 KB)
📄
syslog_ng.py
(31.55 KB)
📄
sysmod.py
(22.59 KB)
📄
sysrc.py
(3.38 KB)
📄
system.py
(19.28 KB)
📄
system_profiler.py
(3.54 KB)
📄
systemd_service.py
(46.19 KB)
📄
telegram.py
(3.28 KB)
📄
telemetry.py
(12.9 KB)
📄
temp.py
(831 B)
📄
test.py
(14.71 KB)
📄
test_virtual.py
(194 B)
📄
testinframod.py
(9.92 KB)
📄
textfsm_mod.py
(16.22 KB)
📄
timezone.py
(19.89 KB)
📄
tls.py
(58.68 KB)
📄
tomcat.py
(18.59 KB)
📄
trafficserver.py
(10.44 KB)
📄
transactional_update.py
(42 KB)
📄
travisci.py
(2.08 KB)
📄
tuned.py
(2.34 KB)
📄
twilio_notify.py
(2.95 KB)
📄
udev.py
(3.72 KB)
📄
upstart_service.py
(16.92 KB)
📄
uptime.py
(3.23 KB)
📄
useradd.py
(22.3 KB)
📄
uwsgi.py
(996 B)
📄
vagrant.py
(20.4 KB)
📄
varnish.py
(3.08 KB)
📄
vault.py
(13.48 KB)
📄
vbox_guest.py
(10.55 KB)
📄
vboxmanage.py
(14.72 KB)
📄
vcenter.py
(455 B)
📄
victorops.py
(6.54 KB)
📄
virt.py
(290.11 KB)
📄
virtualenv_mod.py
(15.08 KB)
📄
vmctl.py
(9.6 KB)
📄
vsphere.py
(376.7 KB)
📄
webutil.py
(3.66 KB)
📄
win_auditpol.py
(4.74 KB)
📄
win_autoruns.py
(2.29 KB)
📄
win_certutil.py
(3.27 KB)
📄
win_dacl.py
(32.27 KB)
📄
win_disk.py
(1.8 KB)
📄
win_dism.py
(18.26 KB)
📄
win_dns_client.py
(4.19 KB)
📄
win_dsc.py
(26.56 KB)
📄
win_file.py
(59.46 KB)
📄
win_firewall.py
(20.15 KB)
📄
win_groupadd.py
(11.27 KB)
📄
win_iis.py
(68.76 KB)
📄
win_ip.py
(11.43 KB)
📄
win_lgpo.py
(491.78 KB)
📄
win_license.py
(2.72 KB)
📄
win_network.py
(14.02 KB)
📄
win_ntp.py
(1.8 KB)
📄
win_path.py
(11.12 KB)
📄
win_pkg.py
(84.64 KB)
📄
win_pki.py
(15.8 KB)
📄
win_powercfg.py
(9.85 KB)
📄
win_psget.py
(8.97 KB)
📄
win_servermanager.py
(14.33 KB)
📄
win_service.py
(32.7 KB)
📄
win_shadow.py
(3.03 KB)
📄
win_smtp_server.py
(17.67 KB)
📄
win_snmp.py
(13.38 KB)
📄
win_status.py
(17.04 KB)
📄
win_system.py
(40.62 KB)
📄
win_task.py
(78.46 KB)
📄
win_timezone.py
(13.27 KB)
📄
win_useradd.py
(27.53 KB)
📄
win_wua.py
(38.29 KB)
📄
win_wusa.py
(5.88 KB)
📄
winrepo.py
(6.3 KB)
📄
wordpress.py
(4.71 KB)
📄
x509.py
(62.22 KB)
📄
xapi_virt.py
(24.08 KB)
📄
xbpspkg.py
(15.89 KB)
📄
xfs.py
(15.33 KB)
📄
xml.py
(2.14 KB)
📄
xmpp.py
(5.28 KB)
📄
yumpkg.py
(112.71 KB)
📄
zabbix.py
(94.11 KB)
📄
zcbuildout.py
(28.19 KB)
📄
zenoss.py
(5.64 KB)
📄
zfs.py
(34.49 KB)
📄
zk_concurrency.py
(11.19 KB)
📄
znc.py
(2.26 KB)
📄
zoneadm.py
(15.11 KB)
📄
zonecfg.py
(21.91 KB)
📄
zookeeper.py
(14.72 KB)
📄
zpool.py
(44.02 KB)
📄
zypperpkg.py
(90.34 KB)
Editing: win_iis.py
""" Microsoft IIS site management via WebAdministration powershell module :maintainer: Shane Lee <slee@saltstack.com>, Robert Booth <rbooth@saltstack.com> :platform: Windows :depends: PowerShell :depends: WebAdministration module (PowerShell) (IIS) .. versionadded:: 2016.3.0 """ import decimal import logging import os import re import salt.utils.json import salt.utils.platform import yaml from salt.exceptions import CommandExecutionError, SaltInvocationError log = logging.getLogger(__name__) _DEFAULT_APP = "/" _VALID_PROTOCOLS = ("ftp", "http", "https") _VALID_SSL_FLAGS = tuple(range(0, 4)) # Define the module's virtual name __virtualname__ = "win_iis" def __virtual__(): """ Load only on Windows Requires PowerShell and the WebAdministration module """ if not salt.utils.platform.is_windows(): return False, "Only available on Windows systems" powershell_info = __salt__["cmd.shell_info"]("powershell", True) if not powershell_info["installed"]: return False, "PowerShell not available" if "WebAdministration" not in powershell_info["modules"]: return False, "IIS is not installed" return __virtualname__ def _get_binding_info(host_header="", ip_address="*", port=80): """ Combine the host header, IP address, and TCP port into bindingInformation format. Binding Information specifies information to communicate with a site. It includes the IP address, the port number, and an optional host header (usually a host name) to communicate with the site. Args: host_header (str): Usually a hostname ip_address (str): The IP address port (int): The port Returns: str: A properly formatted bindingInformation string (IP:port:hostheader) eg: 192.168.0.12:80:www.contoso.com """ return ":".join([ip_address, str(port), host_header.replace(" ", "")]) def _list_certs(certificate_store="My"): """ List details of available certificates in the LocalMachine certificate store. Args: certificate_store (str): The name of the certificate store on the local machine. Returns: dict: A dictionary of certificates found in the store """ ret = dict() blacklist_keys = ["DnsNameList", "Thumbprint"] ps_cmd = [ "Get-ChildItem", "-Path", r"'Cert:\LocalMachine\{}'".format(certificate_store), "|", "Select-Object DnsNameList, SerialNumber, Subject, Thumbprint, Version", ] cmd_ret = _srvmgr(cmd=ps_cmd, return_json=True) try: items = salt.utils.json.loads(cmd_ret["stdout"], strict=False) except ValueError: raise CommandExecutionError("Unable to parse return data as Json.") for item in items: cert_info = dict() for key in item: if key not in blacklist_keys: cert_info[key.lower()] = item[key] cert_info["dnsnames"] = [] if item["DnsNameList"]: cert_info["dnsnames"] = [name["Unicode"] for name in item["DnsNameList"]] ret[item["Thumbprint"]] = cert_info return ret def _iisVersion(): pscmd = [] pscmd.append(r"Get-ItemProperty HKLM:\\SOFTWARE\\Microsoft\\InetStp\\") pscmd.append(" | Select-Object MajorVersion, MinorVersion") cmd_ret = _srvmgr(pscmd, return_json=True) try: items = salt.utils.json.loads(cmd_ret["stdout"], strict=False) except ValueError: log.error("Unable to parse return data as Json.") return -1 return decimal.Decimal( "{}.{}".format(items[0]["MajorVersion"], items[0]["MinorVersion"]) ) def _srvmgr(cmd, return_json=False): """ Execute a powershell command from the WebAdministration PS module. Args: cmd (list): The command to execute in a list return_json (bool): True formats the return in JSON, False just returns the output of the command. Returns: str: The output from the command """ if isinstance(cmd, list): cmd = " ".join(cmd) if return_json: cmd = "ConvertTo-Json -Compress -Depth 4 -InputObject @({})".format(cmd) cmd = "Import-Module WebAdministration; {}".format(cmd) ret = __salt__["cmd.run_all"](cmd, shell="powershell", python_shell=True) if ret["retcode"] != 0: log.error("Unable to execute command: %s\nError: %s", cmd, ret["stderr"]) return ret def _collection_match_to_index(pspath, colfilter, name, match): """ Returns index of collection item matching the match dictionary. """ collection = get_webconfiguration_settings( pspath, [{"name": name, "filter": colfilter}] )[0]["value"] for idx, collect_dict in enumerate(collection): if all(item in collect_dict.items() for item in match.items()): return idx return -1 def _prepare_settings(pspath, settings): """ Prepare settings before execution with get or set functions. Removes settings with a match parameter when index is not found. """ prepared_settings = [] for setting in settings: if setting.get("name", None) is None: log.warning("win_iis: Setting has no name: %s", setting) continue if setting.get("filter", None) is None: log.warning("win_iis: Setting has no filter: %s", setting) continue match = re.search(r"Collection\[(\{.*\})\]", setting["name"]) if match: name = setting["name"][: match.start(1) - 1] match_dict = yaml.load(match.group(1)) index = _collection_match_to_index( pspath, setting["filter"], name, match_dict ) if index == -1: log.warning("win_iis: No match found for setting: %s", setting) else: setting["name"] = setting["name"].replace(match.group(1), str(index)) prepared_settings.append(setting) else: prepared_settings.append(setting) return prepared_settings def list_sites(): """ List all the currently deployed websites. Returns: dict: A dictionary of the IIS sites and their properties. CLI Example: .. code-block:: bash salt '*' win_iis.list_sites """ ret = dict() ps_cmd = [ "Get-ChildItem", "-Path", r"'IIS:\Sites'", "|", "Select-Object applicationPool, Bindings, ID, Name, PhysicalPath, State", ] keep_keys = ("certificateHash", "certificateStoreName", "protocol", "sslFlags") cmd_ret = _srvmgr(cmd=ps_cmd, return_json=True) try: items = salt.utils.json.loads(cmd_ret["stdout"], strict=False) except ValueError: raise CommandExecutionError("Unable to parse return data as Json.") for item in items: bindings = dict() for binding in item["bindings"]["Collection"]: # Ignore bindings which do not have host names if binding["protocol"] not in ["http", "https"]: continue filtered_binding = dict() for key in binding: if key in keep_keys: filtered_binding.update({key.lower(): binding[key]}) binding_info = binding["bindingInformation"].split(":", 2) ipaddress, port, hostheader = [element.strip() for element in binding_info] filtered_binding.update( {"hostheader": hostheader, "ipaddress": ipaddress, "port": port} ) bindings[binding["bindingInformation"]] = filtered_binding ret[item["name"]] = { "apppool": item["applicationPool"], "bindings": bindings, "id": item["id"], "state": item["state"], "sourcepath": item["physicalPath"], } if not ret: log.warning("No sites found in output: %s", cmd_ret["stdout"]) return ret def create_site( name, sourcepath, apppool="", hostheader="", ipaddress="*", port=80, protocol="http" ): """ Create a basic website in IIS. .. note:: This function only validates against the site name, and will return True even if the site already exists with a different configuration. It will not modify the configuration of an existing site. Args: name (str): The IIS site name. sourcepath (str): The physical path of the IIS site. apppool (str): The name of the IIS application pool. hostheader (str): The host header of the binding. Usually the hostname or website name, ie: www.contoso.com ipaddress (str): The IP address of the binding. port (int): The TCP port of the binding. protocol (str): The application protocol of the binding. (http, https, etc.) Returns: bool: True if successful, otherwise False. .. note:: If an application pool is specified, and that application pool does not already exist, it will be created. CLI Example: .. code-block:: bash salt '*' win_iis.create_site name='My Test Site' sourcepath='c:\\stage' apppool='TestPool' """ protocol = str(protocol).lower() site_path = r"IIS:\Sites\{}".format(name) binding_info = _get_binding_info(hostheader, ipaddress, port) current_sites = list_sites() if name in current_sites: log.debug("Site '%s' already present.", name) return True if protocol not in _VALID_PROTOCOLS: message = "Invalid protocol '{}' specified. Valid formats: {}".format( protocol, _VALID_PROTOCOLS ) raise SaltInvocationError(message) ps_cmd = [ "New-Item", "-Path", r"'{}'".format(site_path), "-PhysicalPath", r"'{}'".format(sourcepath), "-Bindings", "@{{ protocol='{0}'; bindingInformation='{1}' }};".format( protocol, binding_info ), ] if apppool: if apppool in list_apppools(): log.debug("Utilizing pre-existing application pool: %s", apppool) else: log.debug("Application pool will be created: %s", apppool) create_apppool(apppool) ps_cmd.extend( [ "Set-ItemProperty", "-Path", "'{}'".format(site_path), "-Name", "ApplicationPool", "-Value", "'{}'".format(apppool), ] ) cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to create site: {}\nError: {}".format(name, cmd_ret["stderr"]) raise CommandExecutionError(msg) log.debug("Site created successfully: %s", name) return True def modify_site(name, sourcepath=None, apppool=None): """ Modify a basic website in IIS. .. versionadded:: 2017.7.0 Args: name (str): The IIS site name. sourcepath (str): The physical path of the IIS site. apppool (str): The name of the IIS application pool. Returns: bool: True if successful, otherwise False. .. note:: If an application pool is specified, and that application pool does not already exist, it will be created. CLI Example: .. code-block:: bash salt '*' win_iis.modify_site name='My Test Site' sourcepath='c:\\new_path' apppool='NewTestPool' """ site_path = r"IIS:\Sites\{}".format(name) current_sites = list_sites() if name not in current_sites: log.debug("Site '%s' not defined.", name) return False ps_cmd = list() if sourcepath: ps_cmd.extend( [ "Set-ItemProperty", "-Path", r"'{}'".format(site_path), "-Name", "PhysicalPath", "-Value", r"'{}'".format(sourcepath), ] ) if apppool: if apppool in list_apppools(): log.debug("Utilizing pre-existing application pool: %s", apppool) else: log.debug("Application pool will be created: %s", apppool) create_apppool(apppool) # If ps_cmd isn't empty, we need to add a semi-colon to run two commands if ps_cmd: ps_cmd.append(";") ps_cmd.extend( [ "Set-ItemProperty", "-Path", r"'{}'".format(site_path), "-Name", "ApplicationPool", "-Value", r"'{}'".format(apppool), ] ) cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to modify site: {}\nError: {}".format(name, cmd_ret["stderr"]) raise CommandExecutionError(msg) log.debug("Site modified successfully: %s", name) return True def remove_site(name): """ Delete a website from IIS. Args: name (str): The IIS site name. Returns: bool: True if successful, otherwise False .. note:: This will not remove the application pool used by the site. CLI Example: .. code-block:: bash salt '*' win_iis.remove_site name='My Test Site' """ current_sites = list_sites() if name not in current_sites: log.debug("Site already absent: %s", name) return True ps_cmd = ["Remove-WebSite", "-Name", r"'{}'".format(name)] cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to remove site: {}\nError: {}".format(name, cmd_ret["stderr"]) raise CommandExecutionError(msg) log.debug("Site removed successfully: %s", name) return True def stop_site(name): """ Stop a Web Site in IIS. .. versionadded:: 2017.7.0 Args: name (str): The name of the website to stop. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.stop_site name='My Test Site' """ ps_cmd = ["Stop-WebSite", r"'{}'".format(name)] cmd_ret = _srvmgr(ps_cmd) return cmd_ret["retcode"] == 0 def start_site(name): """ Start a Web Site in IIS. .. versionadded:: 2017.7.0 Args: name (str): The name of the website to start. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.start_site name='My Test Site' """ ps_cmd = ["Start-WebSite", r"'{}'".format(name)] cmd_ret = _srvmgr(ps_cmd) return cmd_ret["retcode"] == 0 def restart_site(name): """ Restart a Web Site in IIS. .. versionadded:: 2017.7.0 Args: name (str): The name of the website to restart. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.restart_site name='My Test Site' """ return stop_site(name) and start_site(name) def list_bindings(site): """ Get all configured IIS bindings for the specified site. Args: site (str): The name if the IIS Site Returns: dict: A dictionary of the binding names and properties. CLI Example: .. code-block:: bash salt '*' win_iis.list_bindings site """ ret = dict() sites = list_sites() if site not in sites: log.warning("Site not found: %s", site) return ret ret = sites[site]["bindings"] if not ret: log.warning("No bindings found for site: %s", site) return ret def create_binding( site, hostheader="", ipaddress="*", port=80, protocol="http", sslflags=None ): """ Create an IIS Web Binding. .. note:: This function only validates against the binding ipaddress:port:hostheader combination, and will return True even if the binding already exists with a different configuration. It will not modify the configuration of an existing binding. Args: site (str): The IIS site name. hostheader (str): The host header of the binding. Usually a hostname. ipaddress (str): The IP address of the binding. port (int): The TCP port of the binding. protocol (str): The application protocol of the binding. sslflags (str): The flags representing certificate type and storage of the binding. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.create_binding site='site0' hostheader='example.com' ipaddress='*' port='80' """ protocol = str(protocol).lower() name = _get_binding_info(hostheader, ipaddress, port) if protocol not in _VALID_PROTOCOLS: message = "Invalid protocol '{}' specified. Valid formats: {}".format( protocol, _VALID_PROTOCOLS ) raise SaltInvocationError(message) if sslflags: sslflags = int(sslflags) if sslflags not in _VALID_SSL_FLAGS: raise SaltInvocationError( "Invalid sslflags '{}' specified. Valid sslflags range: {}..{}".format( sslflags, _VALID_SSL_FLAGS[0], _VALID_SSL_FLAGS[-1] ) ) current_bindings = list_bindings(site) if name in current_bindings: log.debug("Binding already present: %s", name) return True if sslflags: ps_cmd = [ "New-WebBinding", "-Name", "'{}'".format(site), "-HostHeader", "'{}'".format(hostheader), "-IpAddress", "'{}'".format(ipaddress), "-Port", "'{}'".format(port), "-Protocol", "'{}'".format(protocol), "-SslFlags", "{}".format(sslflags), ] else: ps_cmd = [ "New-WebBinding", "-Name", "'{}'".format(site), "-HostHeader", "'{}'".format(hostheader), "-IpAddress", "'{}'".format(ipaddress), "-Port", "'{}'".format(port), "-Protocol", "'{}'".format(protocol), ] cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to create binding: {}\nError: {}".format(site, cmd_ret["stderr"]) raise CommandExecutionError(msg) if name in list_bindings(site): log.debug("Binding created successfully: %s", site) return True log.error("Unable to create binding: %s", site) return False def modify_binding( site, binding, hostheader=None, ipaddress=None, port=None, sslflags=None ): """ Modify an IIS Web Binding. Use ``site`` and ``binding`` to target the binding. .. versionadded:: 2017.7.0 Args: site (str): The IIS site name. binding (str): The binding to edit. This is a combination of the IP address, port, and hostheader. It is in the following format: ipaddress:port:hostheader. For example, ``*:80:`` or ``*:80:salt.com`` hostheader (str): The host header of the binding. Usually the hostname. ipaddress (str): The IP address of the binding. port (int): The TCP port of the binding. sslflags (str): The flags representing certificate type and storage of the binding. Returns: bool: True if successful, otherwise False CLI Example: The following will seat the host header of binding ``*:80:`` for ``site0`` to ``example.com`` .. code-block:: bash salt '*' win_iis.modify_binding site='site0' binding='*:80:' hostheader='example.com' """ if sslflags is not None and sslflags not in _VALID_SSL_FLAGS: raise SaltInvocationError( "Invalid sslflags '{}' specified. Valid sslflags range: {}..{}".format( sslflags, _VALID_SSL_FLAGS[0], _VALID_SSL_FLAGS[-1] ) ) current_sites = list_sites() if site not in current_sites: log.debug("Site '%s' not defined.", site) return False current_bindings = list_bindings(site) if binding not in current_bindings: log.debug("Binding '%s' not defined.", binding) return False # Split out the binding so we can insert new ones # Use the existing value if not passed i, p, h = binding.split(":") new_binding = ":".join( [ ipaddress if ipaddress is not None else i, str(port) if port is not None else str(p), hostheader if hostheader is not None else h, ] ) if new_binding != binding: ps_cmd = [ "Set-WebBinding", "-Name", "'{}'".format(site), "-BindingInformation", "'{}'".format(binding), "-PropertyName", "BindingInformation", "-Value", "'{}'".format(new_binding), ] cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to modify binding: {}\nError: {}".format( binding, cmd_ret["stderr"] ) raise CommandExecutionError(msg) if ( sslflags is not None and sslflags != current_sites[site]["bindings"][binding]["sslflags"] ): ps_cmd = [ "Set-WebBinding", "-Name", "'{}'".format(site), "-BindingInformation", "'{}'".format(new_binding), "-PropertyName", "sslflags", "-Value", "'{}'".format(sslflags), ] cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to modify binding SSL Flags: {}\nError: {}".format( sslflags, cmd_ret["stderr"] ) raise CommandExecutionError(msg) log.debug("Binding modified successfully: %s", binding) return True def remove_binding(site, hostheader="", ipaddress="*", port=80): """ Remove an IIS binding. Args: site (str): The IIS site name. hostheader (str): The host header of the binding. ipaddress (str): The IP address of the binding. port (int): The TCP port of the binding. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.remove_binding site='site0' hostheader='example.com' ipaddress='*' port='80' """ name = _get_binding_info(hostheader, ipaddress, port) current_bindings = list_bindings(site) if name not in current_bindings: log.debug("Binding already absent: %s", name) return True ps_cmd = [ "Remove-WebBinding", "-HostHeader", "'{}'".format(hostheader), "-IpAddress", "'{}'".format(ipaddress), "-Port", "'{}'".format(port), ] cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to remove binding: {}\nError: {}".format(site, cmd_ret["stderr"]) raise CommandExecutionError(msg) if name not in list_bindings(site): log.debug("Binding removed successfully: %s", site) return True log.error("Unable to remove binding: %s", site) return False def list_cert_bindings(site): """ List certificate bindings for an IIS site. .. versionadded:: 2016.11.0 Args: site (str): The IIS site name. Returns: dict: A dictionary of the binding names and properties. CLI Example: .. code-block:: bash salt '*' win_iis.list_bindings site """ ret = dict() sites = list_sites() if site not in sites: log.warning("Site not found: %s", site) return ret for binding in sites[site]["bindings"]: if sites[site]["bindings"][binding]["certificatehash"]: ret[binding] = sites[site]["bindings"][binding] if not ret: log.warning("No certificate bindings found for site: %s", site) return ret def create_cert_binding(name, site, hostheader="", ipaddress="*", port=443, sslflags=0): """ Assign a certificate to an IIS Web Binding. .. versionadded:: 2016.11.0 .. note:: The web binding that the certificate is being assigned to must already exist. Args: name (str): The thumbprint of the certificate. site (str): The IIS site name. hostheader (str): The host header of the binding. ipaddress (str): The IP address of the binding. port (int): The TCP port of the binding. sslflags (int): Flags representing certificate type and certificate storage of the binding. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.create_cert_binding name='AAA000' site='site0' hostheader='example.com' ipaddress='*' port='443' """ name = str(name).upper() binding_info = _get_binding_info(hostheader, ipaddress, port) if _iisVersion() < 8: # IIS 7.5 and earlier don't support SNI for HTTPS, therefore cert bindings don't contain the host header binding_info = binding_info.rpartition(":")[0] + ":" binding_path = r"IIS:\SslBindings\{}".format(binding_info.replace(":", "!")) if sslflags not in _VALID_SSL_FLAGS: raise SaltInvocationError( "Invalid sslflags '{}' specified. Valid sslflags range: {}..{}".format( sslflags, _VALID_SSL_FLAGS[0], _VALID_SSL_FLAGS[-1] ) ) # Verify that the target binding exists. current_bindings = list_bindings(site) if binding_info not in current_bindings: log.error("Binding not present: %s", binding_info) return False # Check to see if the certificate is already assigned. current_name = None for current_binding in current_bindings: if binding_info == current_binding: current_name = current_bindings[current_binding]["certificatehash"] log.debug("Current certificate thumbprint: %s", current_name) log.debug("New certificate thumbprint: %s", name) if name == current_name: log.debug("Certificate already present for binding: %s", name) return True # Verify that the certificate exists. certs = _list_certs() if name not in certs: log.error("Certificate not present: %s", name) return False if _iisVersion() < 8: # IIS 7.5 and earlier have different syntax for associating a certificate with a site # Modify IP spec to IIS 7.5 format iis7path = binding_path.replace(r"\*!", "\\0.0.0.0!") # win 2008 uses the following format: ip!port and not ip!port! if iis7path.endswith("!"): iis7path = iis7path[:-1] ps_cmd = [ "New-Item", "-Path", "'{}'".format(iis7path), "-Thumbprint", "'{}'".format(name), ] else: ps_cmd = [ "New-Item", "-Path", "'{}'".format(binding_path), "-Thumbprint", "'{}'".format(name), "-SSLFlags", "{}".format(sslflags), ] cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to create certificate binding: {}\nError: {}".format( name, cmd_ret["stderr"] ) raise CommandExecutionError(msg) new_cert_bindings = list_cert_bindings(site) if binding_info not in new_cert_bindings: log.error("Binding not present: %s", binding_info) return False if name == new_cert_bindings[binding_info]["certificatehash"]: log.debug("Certificate binding created successfully: %s", name) return True log.error("Unable to create certificate binding: %s", name) return False def remove_cert_binding(name, site, hostheader="", ipaddress="*", port=443): """ Remove a certificate from an IIS Web Binding. .. versionadded:: 2016.11.0 .. note:: This function only removes the certificate from the web binding. It does not remove the web binding itself. Args: name (str): The thumbprint of the certificate. site (str): The IIS site name. hostheader (str): The host header of the binding. ipaddress (str): The IP address of the binding. port (int): The TCP port of the binding. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.remove_cert_binding name='AAA000' site='site0' hostheader='example.com' ipaddress='*' port='443' """ name = str(name).upper() binding_info = _get_binding_info(hostheader, ipaddress, port) # Child items of IIS:\SslBindings do not return populated host header info # in all circumstances, so it's necessary to use IIS:\Sites instead. ps_cmd = [ "$Site = Get-ChildItem", "-Path", r"'IIS:\Sites'", "|", "Where-Object", r" {{ $_.Name -Eq '{0}' }};".format(site), "$Binding = $Site.Bindings.Collection", r"| Where-Object { $_.bindingInformation", r"-Eq '{0}' }};".format(binding_info), "$Binding.RemoveSslCertificate()", ] # Verify that the binding exists for the site, and that the target # certificate is assigned to the binding. current_cert_bindings = list_cert_bindings(site) if binding_info not in current_cert_bindings: log.warning("Binding not found: %s", binding_info) return True if name != current_cert_bindings[binding_info]["certificatehash"]: log.debug("Certificate binding already absent: %s", name) return True cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to remove certificate binding: {}\nError: {}".format( name, cmd_ret["stderr"] ) raise CommandExecutionError(msg) new_cert_bindings = list_cert_bindings(site) if binding_info not in new_cert_bindings: log.warning("Binding not found: %s", binding_info) return True if name != new_cert_bindings[binding_info]["certificatehash"]: log.debug("Certificate binding removed successfully: %s", name) return True log.error("Unable to remove certificate binding: %s", name) return False def list_apppools(): """ List all configured IIS application pools. Returns: dict: A dictionary of IIS application pools and their details. CLI Example: .. code-block:: bash salt '*' win_iis.list_apppools """ ret = dict() ps_cmd = [] ps_cmd.append(r"Get-ChildItem -Path 'IIS:\AppPools' | Select-Object Name, State") # Include the equivalent of output from the Applications column, since this # isn't a normal property, we have to populate it via filtered output from # the Get-WebConfigurationProperty cmdlet. ps_cmd.append(r", @{ Name = 'Applications'; Expression = { $AppPool = $_.Name;") ps_cmd.append("$AppPath = 'machine/webroot/apphost';") ps_cmd.append("$FilterBase = '/system.applicationHost/sites/site/application';") ps_cmd.append("$FilterBase += \"[@applicationPool = '$($AppPool)' and @path\";") ps_cmd.append("$FilterRoot = \"$($FilterBase) = '/']/parent::*\";") ps_cmd.append("$FilterNonRoot = \"$($FilterBase) != '/']\";") ps_cmd.append( "Get-WebConfigurationProperty -Filter $FilterRoot -PsPath $AppPath -Name Name" ) ps_cmd.append(r"| ForEach-Object { $_.Value };") ps_cmd.append( "Get-WebConfigurationProperty -Filter $FilterNonRoot -PsPath $AppPath -Name" " Path" ) ps_cmd.append(r"| ForEach-Object { $_.Value } | Where-Object { $_ -ne '/' }") ps_cmd.append("} }") cmd_ret = _srvmgr(cmd=ps_cmd, return_json=True) try: items = salt.utils.json.loads(cmd_ret["stdout"], strict=False) except ValueError: raise CommandExecutionError("Unable to parse return data as Json.") for item in items: applications = list() # If there are no associated apps, Applications will be an empty dict, # if there is one app, it will be a string, and if there are multiple, # it will be a dict with 'Count' and 'value' as the keys. if isinstance(item["Applications"], dict): if "value" in item["Applications"]: applications += item["Applications"]["value"] else: applications.append(item["Applications"]) ret[item["name"]] = {"state": item["state"], "applications": applications} if not ret: log.warning("No application pools found in output: %s", cmd_ret["stdout"]) return ret def create_apppool(name): """ Create an IIS application pool. .. note:: This function only validates against the application pool name, and will return True even if the application pool already exists with a different configuration. It will not modify the configuration of an existing application pool. Args: name (str): The name of the IIS application pool. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.create_apppool name='MyTestPool' """ current_apppools = list_apppools() apppool_path = r"IIS:\AppPools\{}".format(name) if name in current_apppools: log.debug("Application pool '%s' already present.", name) return True ps_cmd = ["New-Item", "-Path", r"'{}'".format(apppool_path)] cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to create application pool: {}\nError: {}".format( name, cmd_ret["stderr"] ) raise CommandExecutionError(msg) log.debug("Application pool created successfully: %s", name) return True def remove_apppool(name): """ Remove an IIS application pool. Args: name (str): The name of the IIS application pool. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.remove_apppool name='MyTestPool' """ current_apppools = list_apppools() apppool_path = r"IIS:\AppPools\{}".format(name) if name not in current_apppools: log.debug("Application pool already absent: %s", name) return True ps_cmd = ["Remove-Item", "-Path", r"'{}'".format(apppool_path), "-Recurse"] cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to remove application pool: {}\nError: {}".format( name, cmd_ret["stderr"] ) raise CommandExecutionError(msg) log.debug("Application pool removed successfully: %s", name) return True def stop_apppool(name): """ Stop an IIS application pool. .. versionadded:: 2017.7.0 Args: name (str): The name of the App Pool to stop. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.stop_apppool name='MyTestPool' """ ps_cmd = ["Stop-WebAppPool", r"'{}'".format(name)] cmd_ret = _srvmgr(ps_cmd) return cmd_ret["retcode"] == 0 def start_apppool(name): """ Start an IIS application pool. .. versionadded:: 2017.7.0 Args: name (str): The name of the App Pool to start. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.start_apppool name='MyTestPool' """ ps_cmd = ["Start-WebAppPool", r"'{}'".format(name)] cmd_ret = _srvmgr(ps_cmd) return cmd_ret["retcode"] == 0 def restart_apppool(name): """ Restart an IIS application pool. .. versionadded:: 2016.11.0 Args: name (str): The name of the IIS application pool. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.restart_apppool name='MyTestPool' """ ps_cmd = ["Restart-WebAppPool", r"'{}'".format(name)] cmd_ret = _srvmgr(ps_cmd) return cmd_ret["retcode"] == 0 def get_container_setting(name, container, settings): """ Get the value of the setting for the IIS container. .. versionadded:: 2016.11.0 Args: name (str): The name of the IIS container. container (str): The type of IIS container. The container types are: AppPools, Sites, SslBindings settings (dict): A dictionary of the setting names and their values. Returns: dict: A dictionary of the provided settings and their values. CLI Example: .. code-block:: bash salt '*' win_iis.get_container_setting name='MyTestPool' container='AppPools' settings="['processModel.identityType']" """ ret = dict() ps_cmd = list() ps_cmd_validate = list() container_path = r"IIS:\{}\{}".format(container, name) if not settings: log.warning("No settings provided") return ret ps_cmd.append(r"$Settings = @{};") for setting in settings: # Build the commands to verify that the property names are valid. ps_cmd_validate.extend( [ "Get-ItemProperty", "-Path", "'{}'".format(container_path), "-Name", "'{}'".format(setting), "-ErrorAction", "Stop", "|", "Out-Null;", ] ) # Some ItemProperties are Strings and others are ConfigurationAttributes. # Since the former doesn't have a Value property, we need to account # for this. ps_cmd.append("$Property = Get-ItemProperty -Path '{}'".format(container_path)) ps_cmd.append("-Name '{}' -ErrorAction Stop;".format(setting)) ps_cmd.append(r"if (([String]::IsNullOrEmpty($Property) -eq $False) -and") ps_cmd.append(r"($Property.GetType()).Name -eq 'ConfigurationAttribute') {") ps_cmd.append(r"$Property = $Property | Select-Object") ps_cmd.append(r"-ExpandProperty Value };") ps_cmd.append("$Settings['{}'] = [String] $Property;".format(setting)) ps_cmd.append(r"$Property = $Null;") # Validate the setting names that were passed in. cmd_ret = _srvmgr(cmd=ps_cmd_validate, return_json=True) if cmd_ret["retcode"] != 0: message = ( "One or more invalid property names were specified for the provided" " container." ) raise SaltInvocationError(message) ps_cmd.append("$Settings") cmd_ret = _srvmgr(cmd=ps_cmd, return_json=True) try: items = salt.utils.json.loads(cmd_ret["stdout"], strict=False) if isinstance(items, list): ret.update(items[0]) else: ret.update(items) except ValueError: raise CommandExecutionError("Unable to parse return data as Json.") return ret def set_container_setting(name, container, settings): """ Set the value of the setting for an IIS container. .. versionadded:: 2016.11.0 Args: name (str): The name of the IIS container. container (str): The type of IIS container. The container types are: AppPools, Sites, SslBindings settings (dict): A dictionary of the setting names and their values. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.set_container_setting name='MyTestPool' container='AppPools' settings="{'managedPipeLineMode': 'Integrated'}" """ identityType_map2string = { "0": "LocalSystem", "1": "LocalService", "2": "NetworkService", "3": "SpecificUser", "4": "ApplicationPoolIdentity", } identityType_map2numeric = { "LocalSystem": "0", "LocalService": "1", "NetworkService": "2", "SpecificUser": "3", "ApplicationPoolIdentity": "4", } ps_cmd = list() container_path = r"IIS:\{}\{}".format(container, name) if not settings: log.warning("No settings provided") return False # Treat all values as strings for the purpose of comparing them to existing values. for setting in settings: settings[setting] = str(settings[setting]) current_settings = get_container_setting( name=name, container=container, settings=settings.keys() ) if settings == current_settings: log.debug("Settings already contain the provided values.") return True for setting in settings: # If the value is numeric, don't treat it as a string in PowerShell. try: complex(settings[setting]) value = settings[setting] except ValueError: value = "'{}'".format(settings[setting]) # Map to numeric to support server 2008 if ( setting == "processModel.identityType" and settings[setting] in identityType_map2numeric.keys() ): value = identityType_map2numeric[settings[setting]] ps_cmd.extend( [ "Set-ItemProperty", "-Path", "'{}'".format(container_path), "-Name", "'{}'".format(setting), "-Value", "{};".format(value), ] ) cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to set settings for {}: {}".format(container, name) raise CommandExecutionError(msg) # Get the fields post-change so that we can verify tht all values # were modified successfully. Track the ones that weren't. new_settings = get_container_setting( name=name, container=container, settings=settings.keys() ) failed_settings = dict() for setting in settings: # map identity type from numeric to string for comparing if ( setting == "processModel.identityType" and settings[setting] in identityType_map2string.keys() ): settings[setting] = identityType_map2string[settings[setting]] if str(settings[setting]) != str(new_settings[setting]): failed_settings[setting] = settings[setting] if failed_settings: log.error("Failed to change settings: %s", failed_settings) return False log.debug("Settings configured successfully: %s", settings.keys()) return True def list_apps(site): """ Get all configured IIS applications for the specified site. Args: site (str): The IIS site name. Returns: A dictionary of the application names and properties. CLI Example: .. code-block:: bash salt '*' win_iis.list_apps site """ ret = dict() ps_cmd = list() ps_cmd.append("Get-WebApplication -Site '{}'".format(site)) ps_cmd.append( r"| Select-Object applicationPool, path, PhysicalPath, preloadEnabled," ) ps_cmd.append(r"@{ Name='name'; Expression={ $_.path.Split('/', 2)[-1] } },") ps_cmd.append( r"@{ Name='protocols'; Expression={ @( $_.enabledProtocols.Split(',')" ) ps_cmd.append(r"| Foreach-Object { $_.Trim() } ) } }") cmd_ret = _srvmgr(cmd=ps_cmd, return_json=True) try: items = salt.utils.json.loads(cmd_ret["stdout"], strict=False) except ValueError: raise CommandExecutionError("Unable to parse return data as Json.") for item in items: protocols = list() # If there are no associated protocols, protocols will be an empty dict, # if there is one protocol, it will be a string, and if there are # multiple, it will be a dict with 'Count' and 'value' as the keys. if isinstance(item["protocols"], dict): if "value" in item["protocols"]: protocols += item["protocols"]["value"] else: protocols.append(item["protocols"]) ret[item["name"]] = { "apppool": item["applicationPool"], "path": item["path"], "preload": item["preloadEnabled"], "protocols": protocols, "sourcepath": item["PhysicalPath"], } if not ret: log.warning("No apps found in output: %s", cmd_ret) return ret def create_app(name, site, sourcepath, apppool=None): """ Create an IIS application. .. note:: This function only validates against the application name, and will return True even if the application already exists with a different configuration. It will not modify the configuration of an existing application. Args: name (str): The IIS application. site (str): The IIS site name. sourcepath (str): The physical path. apppool (str): The name of the IIS application pool. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.create_app name='app0' site='site0' sourcepath='C:\\site0' apppool='site0' """ current_apps = list_apps(site) if name in current_apps: log.debug("Application already present: %s", name) return True # The target physical path must exist. if not os.path.isdir(sourcepath): log.error("Path is not present: %s", sourcepath) return False ps_cmd = [ "New-WebApplication", "-Name", "'{}'".format(name), "-Site", "'{}'".format(site), "-PhysicalPath", "'{}'".format(sourcepath), ] if apppool: ps_cmd.extend(["-ApplicationPool", "'{}'".format(apppool)]) cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to create application: {}\nError: {}".format( name, cmd_ret["stderr"] ) raise CommandExecutionError(msg) new_apps = list_apps(site) if name in new_apps: log.debug("Application created successfully: %s", name) return True log.error("Unable to create application: %s", name) return False def remove_app(name, site): """ Remove an IIS application. Args: name (str): The application name. site (str): The IIS site name. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.remove_app name='app0' site='site0' """ current_apps = list_apps(site) if name not in current_apps: log.debug("Application already absent: %s", name) return True ps_cmd = [ "Remove-WebApplication", "-Name", "'{}'".format(name), "-Site", "'{}'".format(site), ] cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to remove application: {}\nError: {}".format( name, cmd_ret["stderr"] ) raise CommandExecutionError(msg) new_apps = list_apps(site) if name not in new_apps: log.debug("Application removed successfully: %s", name) return True log.error("Unable to remove application: %s", name) return False def list_vdirs(site, app=_DEFAULT_APP): """ Get all configured IIS virtual directories for the specified site, or for the combination of site and application. Args: site (str): The IIS site name. app (str): The IIS application. Returns: dict: A dictionary of the virtual directory names and properties. CLI Example: .. code-block:: bash salt '*' win_iis.list_vdirs site """ ret = dict() ps_cmd = [ "Get-WebVirtualDirectory", "-Site", r"'{}'".format(site), "-Application", r"'{}'".format(app), "|", "Select-Object PhysicalPath, @{ Name = 'name';", r"Expression = { $_.path.Trim('/') } }", ] cmd_ret = _srvmgr(cmd=ps_cmd, return_json=True) try: items = salt.utils.json.loads(cmd_ret["stdout"], strict=False) except ValueError: raise CommandExecutionError("Unable to parse return data as Json.") for item in items: ret[item["name"]] = {"sourcepath": item["physicalPath"]} if not ret: log.warning("No vdirs found in output: %s", cmd_ret) return ret def create_vdir(name, site, sourcepath, app=_DEFAULT_APP): """ Create an IIS virtual directory. .. note:: This function only validates against the virtual directory name, and will return True even if the virtual directory already exists with a different configuration. It will not modify the configuration of an existing virtual directory. Args: name (str): The virtual directory name. site (str): The IIS site name. sourcepath (str): The physical path. app (str): The IIS application. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.create_vdir name='vd0' site='site0' sourcepath='C:\\inetpub\\vdirs\\vd0' """ current_vdirs = list_vdirs(site, app) if name in current_vdirs: log.debug("Virtual directory already present: %s", name) return True # The target physical path must exist. if not os.path.isdir(sourcepath): log.error("Path is not present: %s", sourcepath) return False ps_cmd = [ "New-WebVirtualDirectory", "-Name", r"'{}'".format(name), "-Site", r"'{}'".format(site), "-PhysicalPath", r"'{}'".format(sourcepath), ] if app != _DEFAULT_APP: ps_cmd.extend(["-Application", r"'{}'".format(app)]) cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to create virtual directory: {}\nError: {}".format( name, cmd_ret["stderr"] ) raise CommandExecutionError(msg) new_vdirs = list_vdirs(site, app) if name in new_vdirs: log.debug("Virtual directory created successfully: %s", name) return True log.error("Unable to create virtual directory: %s", name) return False def remove_vdir(name, site, app=_DEFAULT_APP): """ Remove an IIS virtual directory. Args: name (str): The virtual directory name. site (str): The IIS site name. app (str): The IIS application. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.remove_vdir name='vdir0' site='site0' """ current_vdirs = list_vdirs(site, app) app_path = os.path.join(*app.rstrip("/").split("/")) if app_path: app_path = "{}\\".format(app_path) vdir_path = r"IIS:\Sites\{}\{}{}".format(site, app_path, name) if name not in current_vdirs: log.debug("Virtual directory already absent: %s", name) return True # We use Remove-Item here instead of Remove-WebVirtualDirectory, since the # latter has a bug that causes it to always prompt for user input. ps_cmd = ["Remove-Item", "-Path", r"'{}'".format(vdir_path), "-Recurse"] cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to remove virtual directory: {}\nError: {}".format( name, cmd_ret["stderr"] ) raise CommandExecutionError(msg) new_vdirs = list_vdirs(site, app) if name not in new_vdirs: log.debug("Virtual directory removed successfully: %s", name) return True log.error("Unable to remove virtual directory: %s", name) return False def list_backups(): r""" List the IIS Configuration Backups on the System. .. versionadded:: 2017.7.0 .. note:: Backups are made when a configuration is edited. Manual backups are stored in the ``$env:Windir\System32\inetsrv\backup`` folder. Returns: dict: A dictionary of IIS Configurations backed up on the system. CLI Example: .. code-block:: bash salt '*' win_iis.list_backups """ ret = dict() ps_cmd = [ "Get-WebConfigurationBackup", "|", "Select Name, CreationDate,", '@{N="FormattedDate"; E={$_.CreationDate.ToString("G")}}', ] cmd_ret = _srvmgr(cmd=ps_cmd, return_json=True) try: items = salt.utils.json.loads(cmd_ret["stdout"], strict=False) except ValueError: raise CommandExecutionError("Unable to parse return data as Json.") for item in items: if item["FormattedDate"]: ret[item["Name"]] = item["FormattedDate"] else: ret[item["Name"]] = item["CreationDate"] if not ret: log.warning("No backups found in output: %s", cmd_ret) return ret def create_backup(name): r""" Backup an IIS Configuration on the System. .. versionadded:: 2017.7.0 .. note:: Backups are stored in the ``$env:Windir\System32\inetsrv\backup`` folder. Args: name (str): The name to give the backup Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.create_backup good_config_20170209 """ if name in list_backups(): raise CommandExecutionError("Backup already present: {}".format(name)) ps_cmd = ["Backup-WebConfiguration", "-Name", "'{}'".format(name)] cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to backup web configuration: {}\nError: {}".format( name, cmd_ret["stderr"] ) raise CommandExecutionError(msg) return name in list_backups() def remove_backup(name): """ Remove an IIS Configuration backup from the System. .. versionadded:: 2017.7.0 Args: name (str): The name of the backup to remove Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.remove_backup backup_20170209 """ if name not in list_backups(): log.debug("Backup already removed: %s", name) return True ps_cmd = ["Remove-WebConfigurationBackup", "-Name", "'{}'".format(name)] cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to remove web configuration: {}\nError: {}".format( name, cmd_ret["stderr"] ) raise CommandExecutionError(msg) return name not in list_backups() def list_worker_processes(apppool): """ Returns a list of worker processes that correspond to the passed application pool. .. versionadded:: 2017.7.0 Args: apppool (str): The application pool to query Returns: dict: A dictionary of worker processes with their process IDs CLI Example: .. code-block:: bash salt '*' win_iis.list_worker_processes 'My App Pool' """ ps_cmd = ["Get-ChildItem", r"'IIS:\AppPools\{}\WorkerProcesses'".format(apppool)] cmd_ret = _srvmgr(cmd=ps_cmd, return_json=True) try: items = salt.utils.json.loads(cmd_ret["stdout"], strict=False) except ValueError: raise CommandExecutionError("Unable to parse return data as Json.") ret = dict() for item in items: ret[item["processId"]] = item["appPoolName"] if not ret: log.warning("No backups found in output: %s", cmd_ret) return ret def get_webapp_settings(name, site, settings): r""" .. versionadded:: 2017.7.0 Get the value of the setting for the IIS web application. .. note:: Params are case sensitive :param str name: The name of the IIS web application. :param str site: The site name contains the web application. Example: Default Web Site :param str settings: A dictionary of the setting names and their values. Available settings: physicalPath, applicationPool, userName, password Returns: dict: A dictionary of the provided settings and their values. CLI Example: .. code-block:: bash salt '*' win_iis.get_webapp_settings name='app0' site='Default Web Site' settings="['physicalPath','applicationPool']" """ ret = dict() pscmd = list() availableSettings = ("physicalPath", "applicationPool", "userName", "password") if not settings: log.warning("No settings provided") return ret pscmd.append(r"$Settings = @{};") # Verify setting is ine predefined settings and append relevant query command per setting key for setting in settings: if setting in availableSettings: if setting == "userName" or setting == "password": pscmd.append( " $Property = Get-WebConfigurationProperty -Filter" " \"system.applicationHost/sites/site[@name='{}']/application[@path='/{}']/virtualDirectory[@path='/']\"".format( site, name ) ) pscmd.append( r' -Name "{}" -ErrorAction Stop | select Value;'.format(setting) ) pscmd.append( r" $Property = $Property | Select-Object -ExpandProperty Value;" ) pscmd.append(r" $Settings['{}'] = [String] $Property;".format(setting)) pscmd.append(r" $Property = $Null;") if setting == "physicalPath" or setting == "applicationPool": pscmd.append( r" $Property = (get-webapplication {}).{};".format(name, setting) ) pscmd.append(r" $Settings['{}'] = [String] $Property;".format(setting)) pscmd.append(r" $Property = $Null;") else: availSetStr = ", ".join(availableSettings) message = ( "Unexpected setting:" + setting + ". Available settings are: " + availSetStr ) raise SaltInvocationError(message) pscmd.append(" $Settings") # Run commands and return data as json cmd_ret = _srvmgr(cmd="".join(pscmd), return_json=True) # Update dict var to return data try: items = salt.utils.json.loads(cmd_ret["stdout"], strict=False) if isinstance(items, list): ret.update(items[0]) else: ret.update(items) except ValueError: log.error("Unable to parse return data as Json.") if None in ret.values(): message = ( "Some values are empty - please validate site and web application names." " Some commands are case sensitive" ) raise SaltInvocationError(message) return ret def set_webapp_settings(name, site, settings): r""" .. versionadded:: 2017.7.0 Configure an IIS application. .. note:: This function only configures an existing app. Params are case sensitive. :param str name: The IIS application. :param str site: The IIS site name. :param str settings: A dictionary of the setting names and their values. - physicalPath: The physical path of the webapp. - applicationPool: The application pool for the webapp. - userName: "connectAs" user - password: "connectAs" password for user :return: A boolean representing whether all changes succeeded. :rtype: bool CLI Example: .. code-block:: bash salt '*' win_iis.set_webapp_settings name='app0' site='site0' settings="{'physicalPath': 'C:\site0', 'apppool': 'site0'}" """ pscmd = list() current_apps = list_apps(site) current_sites = list_sites() availableSettings = ("physicalPath", "applicationPool", "userName", "password") # Validate params if name not in current_apps: msg = "Application" + name + "doesn't exist" raise SaltInvocationError(msg) if site not in current_sites: msg = "Site" + site + "doesn't exist" raise SaltInvocationError(msg) if not settings: msg = "No settings provided" raise SaltInvocationError(msg) # Treat all values as strings for the purpose of comparing them to existing values & validate settings exists in predefined settings list for setting in settings.keys(): if setting in availableSettings: settings[setting] = str(settings[setting]) else: availSetStr = ", ".join(availableSettings) log.error("Unexpected setting: %s ", setting) log.error("Available settings: %s", availSetStr) msg = "Unexpected setting:" + setting + " Available settings:" + availSetStr raise SaltInvocationError(msg) # Check if settings already configured current_settings = get_webapp_settings( name=name, site=site, settings=settings.keys() ) if settings == current_settings: log.warning("Settings already contain the provided values.") return True for setting in settings: # If the value is numeric, don't treat it as a string in PowerShell. try: complex(settings[setting]) value = settings[setting] except ValueError: value = "'{}'".format(settings[setting]) # Append relevant update command per setting key if setting == "userName" or setting == "password": pscmd.append( " Set-WebConfigurationProperty -Filter" " \"system.applicationHost/sites/site[@name='{}']/application[@path='/{}']/virtualDirectory[@path='/']\"".format( site, name ) ) pscmd.append(' -Name "{}" -Value {};'.format(setting, value)) if setting == "physicalPath" or setting == "applicationPool": pscmd.append( r' Set-ItemProperty "IIS:\Sites\{}\{}" -Name {} -Value {};'.format( site, name, setting, value ) ) if setting == "physicalPath": if not os.path.isdir(settings[setting]): msg = "Path is not present: " + settings[setting] raise SaltInvocationError(msg) # Run commands cmd_ret = _srvmgr(pscmd) # Verify commands completed successfully if cmd_ret["retcode"] != 0: msg = "Unable to set settings for web application {}".format(name) raise SaltInvocationError(msg) # verify changes new_settings = get_webapp_settings(name=name, site=site, settings=settings.keys()) failed_settings = dict() for setting in settings: if str(settings[setting]) != str(new_settings[setting]): failed_settings[setting] = settings[setting] if failed_settings: log.error("Failed to change settings: %s", failed_settings) return False log.debug("Settings configured successfully: %s", list(settings)) return True def get_webconfiguration_settings(name, settings): r""" Get the webconfiguration settings for the IIS PSPath. Args: name (str): The PSPath of the IIS webconfiguration settings. settings (list): A list of dictionaries containing setting name and filter. Returns: dict: A list of dictionaries containing setting name, filter and value. CLI Example: .. code-block:: bash salt '*' win_iis.get_webconfiguration_settings name='IIS:\' settings="[{'name': 'enabled', 'filter': 'system.webServer/security/authentication/anonymousAuthentication'}]" """ ret = {} ps_cmd = [r"$Settings = New-Object System.Collections.ArrayList;"] ps_cmd_validate = [] settings = _prepare_settings(name, settings) if not settings: log.warning("No settings provided") return ret for setting in settings: # Build the commands to verify that the property names are valid. ps_cmd_validate.extend( [ "Get-WebConfigurationProperty", "-PSPath", "'{}'".format(name), "-Filter", "'{}'".format(setting["filter"]), "-Name", "'{}'".format(setting["name"]), "-ErrorAction", "Stop", "|", "Out-Null;", ] ) # Some ItemProperties are Strings and others are ConfigurationAttributes. # Since the former doesn't have a Value property, we need to account # for this. ps_cmd.append( "$Property = Get-WebConfigurationProperty -PSPath '{}'".format(name) ) ps_cmd.append( "-Name '{}' -Filter '{}' -ErrorAction Stop;".format( setting["name"], setting["filter"] ) ) if setting["name"].split(".")[-1] == "Collection": if "value" in setting: ps_cmd.append( "$Property = $Property | select -Property {} ;".format( ",".join(list(setting["value"][0].keys())) ) ) ps_cmd.append( "$Settings.add(@{{filter='{0}';name='{1}';value=[System.Collections.ArrayList]" " @($Property)}})| Out-Null;".format(setting["filter"], setting["name"]) ) else: ps_cmd.append(r"if (([String]::IsNullOrEmpty($Property) -eq $False) -and") ps_cmd.append(r"($Property.GetType()).Name -eq 'ConfigurationAttribute') {") ps_cmd.append(r"$Property = $Property | Select-Object") ps_cmd.append(r"-ExpandProperty Value };") ps_cmd.append( "$Settings.add(@{{filter='{0}';name='{1}';value=[String] $Property}})|" " Out-Null;".format(setting["filter"], setting["name"]) ) ps_cmd.append(r"$Property = $Null;") # Validate the setting names that were passed in. cmd_ret = _srvmgr(cmd=ps_cmd_validate, return_json=True) if cmd_ret["retcode"] != 0: message = ( "One or more invalid property names were specified for the provided" " container." ) raise SaltInvocationError(message) ps_cmd.append("$Settings") cmd_ret = _srvmgr(cmd=ps_cmd, return_json=True) try: ret = salt.utils.json.loads(cmd_ret["stdout"], strict=False) except ValueError: raise CommandExecutionError("Unable to parse return data as Json.") return ret def set_webconfiguration_settings(name, settings): r""" Set the value of the setting for an IIS container. Args: name (str): The PSPath of the IIS webconfiguration settings. settings (list): A list of dictionaries containing setting name, filter and value. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.set_webconfiguration_settings name='IIS:\' settings="[{'name': 'enabled', 'filter': 'system.webServer/security/authentication/anonymousAuthentication', 'value': False}]" """ ps_cmd = [] settings = _prepare_settings(name, settings) if not settings: log.warning("No settings provided") return False # Treat all values as strings for the purpose of comparing them to existing values. for idx, setting in enumerate(settings): if setting["name"].split(".")[-1] != "Collection": settings[idx]["value"] = str(setting["value"]) current_settings = get_webconfiguration_settings(name=name, settings=settings) if settings == current_settings: log.debug("Settings already contain the provided values.") return True for setting in settings: # If the value is numeric, don't treat it as a string in PowerShell. if setting["name"].split(".")[-1] != "Collection": try: complex(setting["value"]) value = setting["value"] except ValueError: value = "'{}'".format(setting["value"]) else: configelement_list = [] for value_item in setting["value"]: configelement_construct = [] for key, value in value_item.items(): configelement_construct.append("{}='{}'".format(key, value)) configelement_list.append( "@{" + ";".join(configelement_construct) + "}" ) value = ",".join(configelement_list) ps_cmd.extend( [ "Set-WebConfigurationProperty", "-PSPath", "'{}'".format(name), "-Filter", "'{}'".format(setting["filter"]), "-Name", "'{}'".format(setting["name"]), "-Value", "{};".format(value), ] ) cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to set settings for {}".format(name) raise CommandExecutionError(msg) # Get the fields post-change so that we can verify tht all values # were modified successfully. Track the ones that weren't. new_settings = get_webconfiguration_settings(name=name, settings=settings) failed_settings = [] for idx, setting in enumerate(settings): is_collection = setting["name"].split(".")[-1] == "Collection" if ( not is_collection and str(setting["value"]) != str(new_settings[idx]["value"]) ) or ( is_collection and list(map(dict, setting["value"])) != list(map(dict, new_settings[idx]["value"])) ): failed_settings.append(setting) if failed_settings: log.error("Failed to change settings: %s", failed_settings) return False log.debug("Settings configured successfully: %s", settings) return True
Upload File
Create Folder