golden hour
/opt/saltstack/salt/lib/python3.10/site-packages/salt/states
⬆️ Go Up
Upload
File/Folder
Size
Actions
__init__.py
25 B
Del
OK
__pycache__
-
Del
OK
acme.py
5.08 KB
Del
OK
alias.py
2.49 KB
Del
OK
alternatives.py
6.75 KB
Del
OK
ansiblegate.py
7.93 KB
Del
OK
apache.py
3.95 KB
Del
OK
apache_conf.py
2.72 KB
Del
OK
apache_module.py
2.73 KB
Del
OK
apache_site.py
2.66 KB
Del
OK
aptpkg.py
1.42 KB
Del
OK
archive.py
68.24 KB
Del
OK
artifactory.py
6.84 KB
Del
OK
at.py
7.48 KB
Del
OK
augeas.py
10.57 KB
Del
OK
aws_sqs.py
2.59 KB
Del
OK
azurearm_compute.py
11.78 KB
Del
OK
azurearm_dns.py
26.05 KB
Del
OK
azurearm_network.py
89.12 KB
Del
OK
azurearm_resource.py
28.23 KB
Del
OK
beacon.py
7.58 KB
Del
OK
bigip.py
96.63 KB
Del
OK
blockdev.py
5.13 KB
Del
OK
boto3_elasticache.py
48.01 KB
Del
OK
boto3_elasticsearch.py
32.58 KB
Del
OK
boto3_route53.py
37.54 KB
Del
OK
boto3_sns.py
12.69 KB
Del
OK
boto_apigateway.py
82.83 KB
Del
OK
boto_asg.py
31.93 KB
Del
OK
boto_cfn.py
11.53 KB
Del
OK
boto_cloudfront.py
6.01 KB
Del
OK
boto_cloudtrail.py
13.18 KB
Del
OK
boto_cloudwatch_alarm.py
6.4 KB
Del
OK
boto_cloudwatch_event.py
12.33 KB
Del
OK
boto_cognitoidentity.py
13.69 KB
Del
OK
boto_datapipeline.py
18.5 KB
Del
OK
boto_dynamodb.py
29.32 KB
Del
OK
boto_ec2.py
71.98 KB
Del
OK
boto_elasticache.py
16.75 KB
Del
OK
boto_elasticsearch_domain.py
12.27 KB
Del
OK
boto_elb.py
55.1 KB
Del
OK
boto_elbv2.py
12.19 KB
Del
OK
boto_iam.py
69.16 KB
Del
OK
boto_iam_role.py
27.12 KB
Del
OK
boto_iot.py
25.33 KB
Del
OK
boto_kinesis.py
16.69 KB
Del
OK
boto_kms.py
12.11 KB
Del
OK
boto_lambda.py
35.52 KB
Del
OK
boto_lc.py
11.04 KB
Del
OK
boto_rds.py
26 KB
Del
OK
boto_route53.py
19.49 KB
Del
OK
boto_s3.py
9.32 KB
Del
OK
boto_s3_bucket.py
24.67 KB
Del
OK
boto_secgroup.py
32.62 KB
Del
OK
boto_sns.py
8.92 KB
Del
OK
boto_sqs.py
7.97 KB
Del
OK
boto_vpc.py
62.23 KB
Del
OK
bower.py
8.26 KB
Del
OK
btrfs.py
10.34 KB
Del
OK
cabal.py
5.73 KB
Del
OK
ceph.py
1.9 KB
Del
OK
chef.py
3.76 KB
Del
OK
chocolatey.py
16.15 KB
Del
OK
chronos_job.py
4.6 KB
Del
OK
cimc.py
14.32 KB
Del
OK
cisconso.py
3.14 KB
Del
OK
cloud.py
14.4 KB
Del
OK
cmd.py
40.92 KB
Del
OK
composer.py
8.38 KB
Del
OK
consul.py
5.4 KB
Del
OK
cron.py
23.39 KB
Del
OK
cryptdev.py
6.17 KB
Del
OK
csf.py
9.98 KB
Del
OK
cyg.py
7.05 KB
Del
OK
ddns.py
4.2 KB
Del
OK
debconfmod.py
6.33 KB
Del
OK
dellchassis.py
24.49 KB
Del
OK
disk.py
6.49 KB
Del
OK
docker_container.py
85.27 KB
Del
OK
docker_image.py
16.7 KB
Del
OK
docker_network.py
36.78 KB
Del
OK
docker_volume.py
6.72 KB
Del
OK
drac.py
4.17 KB
Del
OK
dvs.py
26.29 KB
Del
OK
elasticsearch.py
20.38 KB
Del
OK
elasticsearch_index.py
3.25 KB
Del
OK
elasticsearch_index_template.py
3.67 KB
Del
OK
environ.py
5.81 KB
Del
OK
eselect.py
2.27 KB
Del
OK
esxcluster.py
22.4 KB
Del
OK
esxdatacenter.py
4.44 KB
Del
OK
esxi.py
63.07 KB
Del
OK
esxvm.py
20.11 KB
Del
OK
etcd_mod.py
11 KB
Del
OK
ethtool.py
9.88 KB
Del
OK
event.py
2.48 KB
Del
OK
file.py
316.7 KB
Del
OK
firewall.py
1.33 KB
Del
OK
firewalld.py
26.08 KB
Del
OK
gem.py
7.13 KB
Del
OK
git.py
123.85 KB
Del
OK
github.py
27.25 KB
Del
OK
glance_image.py
2.26 KB
Del
OK
glassfish.py
21.47 KB
Del
OK
glusterfs.py
12.21 KB
Del
OK
gnomedesktop.py
7.47 KB
Del
OK
gpg.py
5.28 KB
Del
OK
grafana.py
12.11 KB
Del
OK
grafana4_dashboard.py
17.31 KB
Del
OK
grafana4_datasource.py
6.15 KB
Del
OK
grafana4_org.py
7.73 KB
Del
OK
grafana4_user.py
5.52 KB
Del
OK
grafana_dashboard.py
17.74 KB
Del
OK
grafana_datasource.py
5.31 KB
Del
OK
grains.py
15.57 KB
Del
OK
group.py
9.84 KB
Del
OK
heat.py
9.69 KB
Del
OK
helm.py
10.39 KB
Del
OK
hg.py
6.33 KB
Del
OK
highstate_doc.py
1.41 KB
Del
OK
host.py
8.64 KB
Del
OK
http.py
7.46 KB
Del
OK
icinga2.py
9.07 KB
Del
OK
idem.py
3.91 KB
Del
OK
ifttt.py
2.12 KB
Del
OK
incron.py
5.71 KB
Del
OK
influxdb08_database.py
2.85 KB
Del
OK
influxdb08_user.py
3.39 KB
Del
OK
influxdb_continuous_query.py
2.83 KB
Del
OK
influxdb_database.py
2.11 KB
Del
OK
influxdb_retention_policy.py
4.82 KB
Del
OK
influxdb_user.py
4.84 KB
Del
OK
infoblox_a.py
4.24 KB
Del
OK
infoblox_cname.py
4.19 KB
Del
OK
infoblox_host_record.py
6.59 KB
Del
OK
infoblox_range.py
6.85 KB
Del
OK
ini_manage.py
12.67 KB
Del
OK
ipmi.py
8.42 KB
Del
OK
ipset.py
9.66 KB
Del
OK
iptables.py
27.65 KB
Del
OK
jboss7.py
23.95 KB
Del
OK
jenkins.py
3.36 KB
Del
OK
junos.py
17.78 KB
Del
OK
kapacitor.py
6.46 KB
Del
OK
kernelpkg.py
6.42 KB
Del
OK
keyboard.py
2.01 KB
Del
OK
keystone.py
27.12 KB
Del
OK
keystone_domain.py
2.81 KB
Del
OK
keystone_endpoint.py
4.69 KB
Del
OK
keystone_group.py
3.25 KB
Del
OK
keystone_project.py
3.36 KB
Del
OK
keystone_role.py
2.33 KB
Del
OK
keystone_role_grant.py
4.08 KB
Del
OK
keystone_service.py
2.89 KB
Del
OK
keystone_user.py
3.47 KB
Del
OK
keystore.py
5.67 KB
Del
OK
kmod.py
8.59 KB
Del
OK
kubernetes.py
24.87 KB
Del
OK
layman.py
2.44 KB
Del
OK
ldap.py
19.78 KB
Del
OK
libcloud_dns.py
5.7 KB
Del
OK
libcloud_loadbalancer.py
5.66 KB
Del
OK
libcloud_storage.py
5.13 KB
Del
OK
linux_acl.py
24.42 KB
Del
OK
locale.py
2.52 KB
Del
OK
logadm.py
4.67 KB
Del
OK
logrotate.py
3.86 KB
Del
OK
loop.py
7.74 KB
Del
OK
lvm.py
13.33 KB
Del
OK
lvs_server.py
6.28 KB
Del
OK
lvs_service.py
4.38 KB
Del
OK
lxc.py
22.17 KB
Del
OK
lxd.py
7.88 KB
Del
OK
lxd_container.py
22.25 KB
Del
OK
lxd_image.py
10.59 KB
Del
OK
lxd_profile.py
7.11 KB
Del
OK
mac_assistive.py
1.55 KB
Del
OK
mac_keychain.py
5.59 KB
Del
OK
mac_xattr.py
3.15 KB
Del
OK
macdefaults.py
2.65 KB
Del
OK
macpackage.py
6.76 KB
Del
OK
makeconf.py
6.87 KB
Del
OK
marathon_app.py
4.45 KB
Del
OK
mdadm_raid.py
6.41 KB
Del
OK
memcached.py
3.95 KB
Del
OK
modjk.py
2.84 KB
Del
OK
modjk_worker.py
6.49 KB
Del
OK
module.py
18.64 KB
Del
OK
mongodb_database.py
1.65 KB
Del
OK
mongodb_user.py
6.26 KB
Del
OK
monit.py
2.68 KB
Del
OK
mount.py
50.32 KB
Del
OK
mssql_database.py
3 KB
Del
OK
mssql_login.py
3.64 KB
Del
OK
mssql_role.py
2.37 KB
Del
OK
mssql_user.py
3.51 KB
Del
OK
msteams.py
2.53 KB
Del
OK
mysql_database.py
6.05 KB
Del
OK
mysql_grants.py
8.49 KB
Del
OK
mysql_query.py
13.07 KB
Del
OK
mysql_user.py
9.51 KB
Del
OK
net_napalm_yang.py
9.15 KB
Del
OK
netacl.py
31.92 KB
Del
OK
netconfig.py
33.42 KB
Del
OK
netntp.py
12.51 KB
Del
OK
netsnmp.py
11.33 KB
Del
OK
netusers.py
16.1 KB
Del
OK
network.py
23.97 KB
Del
OK
neutron_network.py
3.96 KB
Del
OK
neutron_secgroup.py
4 KB
Del
OK
neutron_secgroup_rule.py
4.75 KB
Del
OK
neutron_subnet.py
4.29 KB
Del
OK
nexus.py
4.97 KB
Del
OK
nfs_export.py
4.92 KB
Del
OK
nftables.py
19.5 KB
Del
OK
npm.py
11.21 KB
Del
OK
ntp.py
2.12 KB
Del
OK
nxos.py
10.37 KB
Del
OK
nxos_upgrade.py
3.5 KB
Del
OK
openstack_config.py
3.26 KB
Del
OK
openvswitch_bridge.py
4.36 KB
Del
OK
openvswitch_db.py
2.24 KB
Del
OK
openvswitch_port.py
17.24 KB
Del
OK
opsgenie.py
4.07 KB
Del
OK
pagerduty.py
1.89 KB
Del
OK
pagerduty_escalation_policy.py
5.42 KB
Del
OK
pagerduty_schedule.py
6.09 KB
Del
OK
pagerduty_service.py
3.93 KB
Del
OK
pagerduty_user.py
1.18 KB
Del
OK
panos.py
48.13 KB
Del
OK
pbm.py
20.46 KB
Del
OK
pcs.py
36.46 KB
Del
OK
pdbedit.py
3.43 KB
Del
OK
pecl.py
3.65 KB
Del
OK
pip_state.py
38.55 KB
Del
OK
pkg.py
138.08 KB
Del
OK
pkgbuild.py
11.37 KB
Del
OK
pkgng.py
685 B
Del
OK
pkgrepo.py
27.53 KB
Del
OK
portage_config.py
5.01 KB
Del
OK
ports.py
5.65 KB
Del
OK
postgres_cluster.py
4.19 KB
Del
OK
postgres_database.py
6.08 KB
Del
OK
postgres_extension.py
5.68 KB
Del
OK
postgres_group.py
8.52 KB
Del
OK
postgres_initdb.py
2.84 KB
Del
OK
postgres_language.py
3.94 KB
Del
OK
postgres_privileges.py
7.86 KB
Del
OK
postgres_schema.py
4.34 KB
Del
OK
postgres_tablespace.py
6.62 KB
Del
OK
postgres_user.py
9.49 KB
Del
OK
powerpath.py
2.34 KB
Del
OK
probes.py
15.06 KB
Del
OK
process.py
1.32 KB
Del
OK
proxy.py
4.94 KB
Del
OK
pushover.py
3.13 KB
Del
OK
pyenv.py
6.07 KB
Del
OK
pyrax_queues.py
2.97 KB
Del
OK
quota.py
1.4 KB
Del
OK
rabbitmq_cluster.py
1.84 KB
Del
OK
rabbitmq_plugin.py
2.77 KB
Del
OK
rabbitmq_policy.py
4.59 KB
Del
OK
rabbitmq_upstream.py
7.9 KB
Del
OK
rabbitmq_user.py
8.89 KB
Del
OK
rabbitmq_vhost.py
3.04 KB
Del
OK
rbac_solaris.py
6.67 KB
Del
OK
rbenv.py
7.36 KB
Del
OK
rdp.py
1.28 KB
Del
OK
redismod.py
4.76 KB
Del
OK
reg.py
19.22 KB
Del
OK
restconf.py
6.41 KB
Del
OK
rsync.py
4.45 KB
Del
OK
rvm.py
6.56 KB
Del
OK
salt_proxy.py
1.34 KB
Del
OK
saltmod.py
33.12 KB
Del
OK
saltutil.py
8.91 KB
Del
OK
schedule.py
12.47 KB
Del
OK
selinux.py
18.61 KB
Del
OK
serverdensity_device.py
6.41 KB
Del
OK
service.py
37.89 KB
Del
OK
slack.py
4.98 KB
Del
OK
smartos.py
44.83 KB
Del
OK
smtp.py
2.3 KB
Del
OK
snapper.py
7.24 KB
Del
OK
solrcloud.py
4.48 KB
Del
OK
splunk.py
4.32 KB
Del
OK
splunk_search.py
3.17 KB
Del
OK
sqlite3.py
14.7 KB
Del
OK
ssh_auth.py
19.57 KB
Del
OK
ssh_known_hosts.py
7.92 KB
Del
OK
stateconf.py
494 B
Del
OK
status.py
2.21 KB
Del
OK
statuspage.py
17.29 KB
Del
OK
supervisord.py
10.48 KB
Del
OK
svn.py
8.14 KB
Del
OK
sysctl.py
4.11 KB
Del
OK
sysfs.py
2.13 KB
Del
OK
syslog_ng.py
2.97 KB
Del
OK
sysrc.py
2.82 KB
Del
OK
telemetry_alert.py
7.04 KB
Del
OK
test.py
13.09 KB
Del
OK
testinframod.py
1.35 KB
Del
OK
timezone.py
3.42 KB
Del
OK
tls.py
1.81 KB
Del
OK
tomcat.py
9.72 KB
Del
OK
trafficserver.py
8.82 KB
Del
OK
tuned.py
3.32 KB
Del
OK
uptime.py
1.87 KB
Del
OK
user.py
38.63 KB
Del
OK
vagrant.py
11.4 KB
Del
OK
vault.py
3.28 KB
Del
OK
vbox_guest.py
4.05 KB
Del
OK
victorops.py
3.32 KB
Del
OK
virt.py
80.41 KB
Del
OK
virtualenv_mod.py
11.21 KB
Del
OK
webutil.py
3.89 KB
Del
OK
win_certutil.py
4.8 KB
Del
OK
win_dacl.py
7.96 KB
Del
OK
win_dism.py
14.97 KB
Del
OK
win_dns_client.py
8.32 KB
Del
OK
win_firewall.py
6.87 KB
Del
OK
win_iis.py
31.56 KB
Del
OK
win_lgpo.py
24.99 KB
Del
OK
win_lgpo_reg.py
10.96 KB
Del
OK
win_license.py
1.6 KB
Del
OK
win_network.py
14.18 KB
Del
OK
win_path.py
6.39 KB
Del
OK
win_pki.py
5.56 KB
Del
OK
win_powercfg.py
3.79 KB
Del
OK
win_servermanager.py
10.4 KB
Del
OK
win_shortcut.py
7.81 KB
Del
OK
win_smtp_server.py
10.01 KB
Del
OK
win_snmp.py
6.64 KB
Del
OK
win_system.py
13.78 KB
Del
OK
win_wua.py
16.27 KB
Del
OK
win_wusa.py
3.53 KB
Del
OK
winrepo.py
2.74 KB
Del
OK
wordpress.py
4.82 KB
Del
OK
x509.py
27.86 KB
Del
OK
x509_v2.py
64.78 KB
Del
OK
xml.py
1.75 KB
Del
OK
xmpp.py
2.61 KB
Del
OK
zabbix_action.py
9.35 KB
Del
OK
zabbix_host.py
27.25 KB
Del
OK
zabbix_hostgroup.py
5.64 KB
Del
OK
zabbix_mediatype.py
16.89 KB
Del
OK
zabbix_template.py
35.14 KB
Del
OK
zabbix_user.py
17.6 KB
Del
OK
zabbix_usergroup.py
9.64 KB
Del
OK
zabbix_usermacro.py
9.69 KB
Del
OK
zabbix_valuemap.py
8.11 KB
Del
OK
zcbuildout.py
5.16 KB
Del
OK
zenoss.py
2.89 KB
Del
OK
zfs.py
34.48 KB
Del
OK
zk_concurrency.py
5.81 KB
Del
OK
zone.py
46.48 KB
Del
OK
zookeeper.py
11.55 KB
Del
OK
zpool.py
13.4 KB
Del
OK
Edit: boto_elb.py
""" Manage ELBs .. versionadded:: 2014.7.0 Create and destroy ELBs. Be aware that this interacts with Amazon's services, and so may incur charges. This module uses ``boto``, which can be installed via package, or pip. This module accepts explicit elb credentials but can also utilize IAM roles assigned to the instance through Instance Profiles. Dynamic credentials are then automatically obtained from AWS API and no further configuration is necessary. More information available `here <http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html>`_. If IAM roles are not used you need to specify them either in a pillar file or in the minion's config file: .. code-block:: yaml elb.keyid: GKTADJGHEIQSXMKKRBJ08H elb.key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs It's also possible to specify ``key``, ``keyid`` and ``region`` via a profile, either passed in as a dict, or as a string to pull from pillars or minion config: .. code-block:: yaml myprofile: keyid: GKTADJGHEIQSXMKKRBJ08H key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs region: us-east-1 .. code-block:: yaml Ensure myelb ELB exists: boto_elb.present: - name: myelb - region: us-east-1 - availability_zones: - us-east-1a - us-east-1c - us-east-1d - keyid: GKTADJGHEIQSXMKKRBJ08H - key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs - listeners: - elb_port: 443 instance_port: 80 elb_protocol: HTTPS instance_protocol: HTTP certificate: 'arn:aws:iam::1111111:server-certificate/mycert' policies: - my-ssl-policy - cookie-policy - elb_port: 8210 instance_port: 8210 elb_protocol: TCP - backends: - instance_port: 80 policies: - enable-proxy-protocol - health_check: target: 'HTTP:80/' - attributes: cross_zone_load_balancing: enabled: true access_log: enabled: true s3_bucket_name: 'mybucket' s3_bucket_prefix: 'my-logs' emit_interval: 5 connecting_settings: idle_timeout: 60 - cnames: - name: mycname.example.com. zone: example.com. ttl: 60 - name: myothercname.example.com. zone: example.com. - security_groups: - my-security-group - policies: - policy_name: my-ssl-policy policy_type: SSLNegotiationPolicyType policy: Protocol-TLSv1.2: true Protocol-SSLv3: false Server-Defined-Cipher-Order: true ECDHE-ECDSA-AES128-GCM-SHA256: true - policy_name: cookie-policy policy_type: LBCookieStickinessPolicyType policy: {} # no policy means this is a session cookie - policy_name: enable-proxy-protocol policy_type: ProxyProtocolPolicyType policy: ProxyProtocol: true # Using a profile from pillars Ensure myelb ELB exists: boto_elb.present: - name: myelb - region: us-east-1 - profile: myelbprofile # Passing in a profile Ensure myelb ELB exists: boto_elb.present: - name: myelb - region: us-east-1 - profile: keyid: GKTADJGHEIQSXMKKRBJ08H key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs It's possible to specify attributes from pillars by specifying a pillar. You can override the values defined in the pillard by setting the attributes on the resource. The module will use the default pillar key 'boto_elb_attributes', which allows you to set default attributes for all ELB resources. Setting the attributes pillar: .. code-block:: yaml my_elb_attributes: cross_zone_load_balancing: enabled: true connection_draining: enabled: true timeout: 20 access_log: enabled: true s3_bucket_name: 'mybucket' s3_bucket_prefix: 'my-logs' emit_interval: 5 Overriding the attribute values on the resource: .. code-block:: yaml Ensure myelb ELB exists: boto_elb.present: - name: myelb - region: us-east-1 - attributes_from_pillar: my_elb_attributes # override cross_zone_load_balancing:enabled - attributes: cross_zone_load_balancing: enabled: false - profile: myelbprofile It's possible to specify cloudwatch alarms that will be setup along with the ELB. Note the alarm name will be defined by the name attribute provided, plus the ELB resource name. .. code-block:: yaml Ensure myelb ELB exists: boto_elb.present: - name: myelb - region: us-east-1 - profile: myelbprofile - alarms: UnHealthyHostCount: name: 'ELB UnHealthyHostCount **MANAGED BY SALT**' attributes: metric: UnHealthyHostCount namespace: AWS/ELB statistic: Average comparison: '>=' threshold: 1.0 period: 600 evaluation_periods: 6 unit: null description: ELB UnHealthyHostCount alarm_actions: ['arn:aws:sns:us-east-1:12345:myalarm'] insufficient_data_actions: [] ok_actions: ['arn:aws:sns:us-east-1:12345:myalarm'] You can also use alarms from pillars, and override values from the pillar alarms by setting overrides on the resource. Note that 'boto_elb_alarms' will be used as a default value for all resources, if defined and can be used to ensure alarms are always set for a resource. Setting the alarms in a pillar: .. code-block:: yaml my_elb_alarm: UnHealthyHostCount: name: 'ELB UnHealthyHostCount **MANAGED BY SALT**' attributes: metric: UnHealthyHostCount namespace: AWS/ELB statistic: Average comparison: '>=' threshold: 1.0 period: 600 evaluation_periods: 6 unit: null description: ELB UnHealthyHostCount alarm_actions: ['arn:aws:sns:us-east-1:12345:myalarm'] insufficient_data_actions: [] ok_actions: ['arn:aws:sns:us-east-1:12345:myalarm'] Overriding the alarm values on the resource: .. code-block:: yaml Ensure myelb ELB exists: boto_elb.present: - name: myelb - region: us-east-1 - profile: myelbprofile - alarms_from_pillar: my_elb_alarm # override UnHealthyHostCount:attributes:threshold - alarms: UnHealthyHostCount: attributes: threshold: 2.0 Tags can also be set: .. versionadded:: 2016.3.0 .. code-block:: yaml Ensure myelb ELB exists: boto_elb.present: - name: myelb - region: us-east-1 - profile: myelbprofile - tags: MyTag: 'My Tag Value' OtherTag: 'My Other Value' """ import hashlib import logging import re import salt.utils.data import salt.utils.dictupdate import salt.utils.stringutils from salt.exceptions import SaltInvocationError log = logging.getLogger(__name__) def __virtual__(): """ Only load if boto is available. """ if "boto_elb.exists" in __salt__: return "boto_elb" return (False, "boto_elb module could not be loaded") def present( name, listeners, availability_zones=None, subnets=None, subnet_names=None, security_groups=None, scheme="internet-facing", health_check=None, attributes=None, attributes_from_pillar="boto_elb_attributes", cnames=None, alarms=None, alarms_from_pillar="boto_elb_alarms", policies=None, policies_from_pillar="boto_elb_policies", backends=None, region=None, key=None, keyid=None, profile=None, wait_for_sync=True, tags=None, instance_ids=None, instance_names=None, ): """ Ensure the ELB exists. name Name of the ELB. availability_zones A list of availability zones for this ELB. listeners A list of listener lists; example:: [ ['443', 'HTTPS', 'arn:aws:iam::1111111:server-certificate/mycert'], ['8443', '80', 'HTTPS', 'HTTP', 'arn:aws:iam::1111111:server-certificate/mycert'] ] subnets A list of subnet IDs in your VPC to attach to your LoadBalancer. subnet_names A list of subnet names in your VPC to attach to your LoadBalancer. security_groups The security groups assigned to your LoadBalancer within your VPC. Must be passed either as a list or a comma-separated string. For example, a list: .. code-block:: yaml - security_groups: - secgroup-one - secgroup-two Or as a comma-separated string: .. code-block:: yaml - security_groups: secgroup-one,secgroup-two scheme The type of a LoadBalancer, ``internet-facing`` or ``internal``. Once set, can not be modified. health_check A dict defining the health check for this ELB. attributes A dict defining the attributes to set on this ELB. Unknown keys will be silently ignored. See the :mod:`salt.modules.boto_elb.set_attributes` function for recognized attributes. attributes_from_pillar name of pillar dict that contains attributes. Attributes defined for this specific state will override those from pillar. cnames A list of cname dicts with attributes needed for the DNS add_record state. By default the boto_route53.add_record state will be used, which requires: name, zone, ttl, and identifier. See the boto_route53 state for information about these attributes. Other DNS modules can be called by specifying the provider keyword. the cnames dict will be passed to the state as kwargs. See the :mod:`salt.states.boto_route53` state for information about these attributes. alarms: a dictionary of name->boto_cloudwatch_alarm sections to be associated with this ELB. All attributes should be specified except for dimension which will be automatically set to this ELB. See the :mod:`salt.states.boto_cloudwatch_alarm` state for information about these attributes. alarms_from_pillar: name of pillar dict that contains alarm settings. Alarms defined for this specific state will override those from pillar. region Region to connect to. key Secret key to be used. keyid Access key to be used. profile A dict with region, key and keyid, or a pillar key (string) that contains a dict with region, key and keyid. wait_for_sync Wait for an INSYNC change status from Route53. tags dict of tags instance_ids list of instance ids. The state will ensure that these, and ONLY these, instances are registered with the ELB. This is additive with instance_names. instance_names list of instance names. The state will ensure that these, and ONLY these, instances are registered with the ELB. This is additive with instance_ids. """ # load data from attributes_from_pillar and merge with attributes tmp = __salt__["config.option"](attributes_from_pillar, {}) attributes = salt.utils.dictupdate.update(tmp, attributes) if attributes else tmp ret = {"name": name, "result": True, "comment": "", "changes": {}} if not isinstance(security_groups, (str, list, type(None))): msg = ( "The 'security_group' parameter must be either a list or a " "comma-separated string." ) log.error(msg) ret.update({"comment": msg, "result": False}) return ret if isinstance(security_groups, str): security_groups = security_groups.split(",") _ret = _elb_present( name, availability_zones, listeners, subnets, subnet_names, security_groups, scheme, region, key, keyid, profile, ) ret.update( { "changes": _ret["changes"], "comment": " ".join([ret["comment"], _ret["comment"]]), } ) ret["result"] = ret["result"] if _ret["result"] else _ret["result"] if ret["result"] is False: return ret exists = __salt__["boto_elb.exists"](name, region, key, keyid, profile) if not exists and __opts__["test"]: return ret if attributes: _ret = _attributes_present(name, attributes, region, key, keyid, profile) ret.update( { "changes": salt.utils.dictupdate.update( ret["changes"], _ret["changes"] ), "comment": " ".join([ret["comment"], _ret["comment"]]), } ) ret["result"] = ret["result"] if _ret["result"] else _ret["result"] if ret["result"] is False: return ret _ret = _health_check_present(name, health_check, region, key, keyid, profile) ret.update( { "changes": salt.utils.dictupdate.update(ret["changes"], _ret["changes"]), "comment": " ".join([ret["comment"], _ret["comment"]]), } ) ret["result"] = ret["result"] if _ret["result"] else _ret["result"] if ret["result"] is False: return ret if cnames: lb = __salt__["boto_elb.get_elb_config"](name, region, key, keyid, profile) if lb: for cname in cnames: _ret = None dns_provider = "boto_route53" cname.update({"record_type": "CNAME", "value": lb["dns_name"]}) if "provider" in cname: dns_provider = cname.pop("provider") if dns_provider == "boto_route53": for p in ("profile", "key", "keyid", "region", "wait_for_sync"): cname[p] = locals().get(p) if p not in cname else cname[p] _ret = __states__["boto_route53.present"](**cname) ret.update( { "changes": salt.utils.dictupdate.update( ret["changes"], _ret["changes"] ), "comment": " ".join([ret["comment"], _ret["comment"]]), } ) ret["result"] = ret["result"] if _ret["result"] else _ret["result"] if ret["result"] is False: return ret _ret = _alarms_present( name, alarms, alarms_from_pillar, region, key, keyid, profile ) ret.update( { "changes": salt.utils.dictupdate.update(ret["changes"], _ret["changes"]), "comment": " ".join([ret["comment"], _ret["comment"]]), } ) ret["result"] = ret["result"] if _ret["result"] else _ret["result"] if ret["result"] is False: return ret _ret = _policies_present( name, policies, policies_from_pillar, listeners, backends, region, key, keyid, profile, ) ret.update( { "changes": salt.utils.dictupdate.update(ret["changes"], _ret["changes"]), "comment": " ".join([ret["comment"], _ret["comment"]]), } ) ret["result"] = ret["result"] if _ret["result"] else _ret["result"] if ret["result"] is False: return ret _ret = _tags_present(name, tags, region, key, keyid, profile) ret.update( { "changes": salt.utils.dictupdate.update(ret["changes"], _ret["changes"]), "comment": " ".join([ret["comment"], _ret["comment"]]), } ) ret["result"] = ret["result"] if _ret["result"] else _ret["result"] if ret["result"] is False: return ret if not instance_ids: instance_ids = [] if instance_names: # AWS borks on adding instances in "non-running" states, so filter 'em out. running_states = ("pending", "rebooting", "running", "stopping", "stopped") for n in instance_names: instance_ids += __salt__["boto_ec2.find_instances"]( name=n, region=region, key=key, keyid=keyid, profile=profile, in_states=running_states, ) # Backwards compat: Only touch attached instances if requested (e.g. if some are defined). if instance_ids: if __opts__["test"]: if __salt__["boto_elb.set_instances"]( name, instance_ids, True, region, key, keyid, profile ): ret["comment"] += " ELB {} instances would be updated.".format(name) ret["result"] = None else: success = __salt__["boto_elb.set_instances"]( name, instance_ids, False, region, key, keyid, profile ) if not success: ret["comment"] += "Failed to set requested instances." ret["result"] = False return ret def register_instances( name, instances, region=None, key=None, keyid=None, profile=None ): """ Add EC2 instance(s) to an Elastic Load Balancer. Removing an instance from the ``instances`` list does not remove it from the ELB. name The name of the Elastic Load Balancer to add EC2 instances to. instances A list of EC2 instance IDs that this Elastic Load Balancer should distribute traffic to. This state will only ever append new instances to the ELB. EC2 instances already associated with this ELB will not be removed if they are not in the ``instances`` list. .. versionadded:: 2015.8.0 .. code-block:: yaml add-instances: boto_elb.register_instances: - name: myloadbalancer - instances: - instance-id1 - instance-id2 """ ret = {"name": name, "result": True, "comment": "", "changes": {}} lb = __salt__["boto_elb.exists"](name, region, key, keyid, profile) if not lb: msg = "Could not find lb {}".format(name) log.error(msg) ret.update({"comment": msg, "result": False}) return ret health = __salt__["boto_elb.get_instance_health"](name, region, key, keyid, profile) nodes = [ value["instance_id"] for value in health if value["description"] != "Instance deregistration currently in progress." ] new = [value for value in instances if value not in nodes] if not new: msg = "Instance/s {} already exist.".format(str(instances).strip("[]")) log.debug(msg) ret.update({"comment": msg}) return ret if __opts__["test"]: ret["comment"] = "ELB {} is set to register : {}.".format(name, new) ret["result"] = None return ret state = __salt__["boto_elb.register_instances"]( name, instances, region, key, keyid, profile ) if state: msg = "Load Balancer {} has been changed".format(name) log.info(msg) new = set().union(nodes, instances) ret.update( { "comment": msg, "changes": {"old": "\n".join(nodes), "new": "\n".join(list(new))}, } ) else: msg = "Load balancer {} failed to add instances".format(name) log.error(msg) ret.update({"comment": msg, "result": False}) return ret DEFAULT_PILLAR_LISTENER_POLICY_KEY = "boto_elb_listener_policies" def _elb_present( name, availability_zones, listeners, subnets, subnet_names, security_groups, scheme, region, key, keyid, profile, ): ret = {"result": True, "comment": "", "changes": {}} if not salt.utils.data.exactly_one((availability_zones, subnets, subnet_names)): raise SaltInvocationError( "Exactly one of availability_zones, subnets, " "subnet_names must be provided as arguments." ) if not listeners: listeners = [] for listener in listeners: if len(listener) < 3: raise SaltInvocationError( "Listeners must have at minimum port," " instance_port and protocol values in" " the provided list." ) if "elb_port" not in listener: raise SaltInvocationError("elb_port is a required value for listeners.") if "instance_port" not in listener: raise SaltInvocationError( "instance_port is a required value for listeners." ) if "elb_protocol" not in listener: raise SaltInvocationError("elb_protocol is a required value for listeners.") listener["elb_protocol"] = listener["elb_protocol"].upper() if listener["elb_protocol"] == "HTTPS" and "certificate" not in listener: raise SaltInvocationError( "certificate is a required value for" " listeners if HTTPS is set for" " elb_protocol." ) # best attempt at principle of least surprise here: # only use the default pillar in cases where we don't explicitly # define policies OR policies_from_pillar on a listener policies = listener.setdefault("policies", []) policies_pillar = listener.get("policies_from_pillar", None) if not policies and policies_pillar is None: policies_pillar = DEFAULT_PILLAR_LISTENER_POLICY_KEY if policies_pillar: policies += __salt__["pillar.get"](policies_pillar, {}).get( listener["elb_protocol"], [] ) # Look up subnet ids from names if provided if subnet_names: subnets = [] for i in subnet_names: r = __salt__["boto_vpc.get_resource_id"]( "subnet", name=i, region=region, key=key, keyid=keyid, profile=profile ) if "error" in r: ret["comment"] = "Error looking up subnet ids: {}".format(r["error"]) ret["result"] = False return ret if "id" not in r: ret["comment"] = "Subnet {} does not exist.".format(i) ret["result"] = False return ret subnets.append(r["id"]) _security_groups = None if subnets: vpc_id = __salt__["boto_vpc.get_subnet_association"]( subnets, region, key, keyid, profile ) vpc_id = vpc_id.get("vpc_id") if not vpc_id: ret["comment"] = "Subnets {} do not map to a valid vpc id.".format(subnets) ret["result"] = False return ret _security_groups = __salt__["boto_secgroup.convert_to_group_ids"]( security_groups, vpc_id=vpc_id, region=region, key=key, keyid=keyid, profile=profile, ) if not _security_groups: ret[ "comment" ] = "Security groups {} do not map to valid security group ids.".format( security_groups ) ret["result"] = False return ret exists = __salt__["boto_elb.exists"](name, region, key, keyid, profile) if not exists: if __opts__["test"]: ret["comment"] = "ELB {} is set to be created.".format(name) ret["result"] = None return ret created = __salt__["boto_elb.create"]( name=name, availability_zones=availability_zones, listeners=listeners, subnets=subnets, security_groups=_security_groups, scheme=scheme, region=region, key=key, keyid=keyid, profile=profile, ) if created: ret["changes"]["old"] = {"elb": None} ret["changes"]["new"] = {"elb": name} ret["comment"] = "ELB {} created.".format(name) else: ret["result"] = False ret["comment"] = "Failed to create {} ELB.".format(name) else: ret["comment"] = "ELB {} present.".format(name) _ret = _security_groups_present( name, _security_groups, region, key, keyid, profile ) ret["changes"] = salt.utils.dictupdate.update(ret["changes"], _ret["changes"]) ret["comment"] = " ".join([ret["comment"], _ret["comment"]]) if not _ret["result"]: ret["result"] = _ret["result"] if ret["result"] is False: return ret _ret = _listeners_present(name, listeners, region, key, keyid, profile) ret["changes"] = salt.utils.dictupdate.update(ret["changes"], _ret["changes"]) ret["comment"] = " ".join([ret["comment"], _ret["comment"]]) if not _ret["result"]: ret["result"] = _ret["result"] if ret["result"] is False: return ret if availability_zones: _ret = _zones_present(name, availability_zones, region, key, keyid, profile) ret["changes"] = salt.utils.dictupdate.update( ret["changes"], _ret["changes"] ) ret["comment"] = " ".join([ret["comment"], _ret["comment"]]) if not _ret["result"]: ret["result"] = _ret["result"] if ret["result"] is False: return ret elif subnets: _ret = _subnets_present(name, subnets, region, key, keyid, profile) ret["changes"] = salt.utils.dictupdate.update( ret["changes"], _ret["changes"] ) ret["comment"] = " ".join([ret["comment"], _ret["comment"]]) if not _ret["result"]: ret["result"] = _ret["result"] return ret def _listeners_present(name, listeners, region, key, keyid, profile): ret = {"result": True, "comment": "", "changes": {}} lb = __salt__["boto_elb.get_elb_config"](name, region, key, keyid, profile) if not lb: ret["comment"] = "{} ELB configuration could not be retrieved.".format(name) ret["result"] = False return ret if not listeners: listeners = [] expected_listeners_by_tuple = {} for l in listeners: l_key = __salt__["boto_elb.listener_dict_to_tuple"](l) expected_listeners_by_tuple[l_key] = l actual_listeners_by_tuple = {} for l in lb["listeners"]: l_key = __salt__["boto_elb.listener_dict_to_tuple"](l) actual_listeners_by_tuple[l_key] = l to_delete = [] to_create = [] for t, l in expected_listeners_by_tuple.items(): if t not in actual_listeners_by_tuple: to_create.append(l) for t, l in actual_listeners_by_tuple.items(): if t not in expected_listeners_by_tuple: to_delete.append(l) if __opts__["test"]: msg = [] if to_create or to_delete: msg.append("ELB {} set to have listeners modified:".format(name)) for listener in to_create: msg.append( "Listener {} added.".format( __salt__["boto_elb.listener_dict_to_tuple"](listener) ) ) for listener in to_delete: msg.append( "Listener {} deleted.".format( __salt__["boto_elb.listener_dict_to_tuple"](listener) ) ) ret["result"] = None else: msg.append("Listeners already set on ELB {}.".format(name)) ret["comment"] = " ".join(msg) return ret if to_delete: ports = [l["elb_port"] for l in to_delete] deleted = __salt__["boto_elb.delete_listeners"]( name, ports, region, key, keyid, profile ) if deleted: ret["comment"] = "Deleted listeners on {} ELB.".format(name) else: ret["comment"] = "Failed to delete listeners on {} ELB.".format(name) ret["result"] = False if to_create: created = __salt__["boto_elb.create_listeners"]( name, to_create, region, key, keyid, profile ) if created: msg = "Created listeners on {0} ELB." ret["comment"] = " ".join([ret["comment"], msg.format(name)]) else: msg = "Failed to create listeners on {0} ELB." ret["comment"] = " ".join([ret["comment"], msg.format(name)]) ret["result"] = False if to_create or to_delete: ret["changes"]["listeners"] = {} ret["changes"]["listeners"]["old"] = lb["listeners"] lb = __salt__["boto_elb.get_elb_config"](name, region, key, keyid, profile) ret["changes"]["listeners"]["new"] = lb["listeners"] else: ret["comment"] = "Listeners already set on ELB {}.".format(name) return ret def _security_groups_present(name, security_groups, region, key, keyid, profile): ret = {"result": True, "comment": "", "changes": {}} lb = __salt__["boto_elb.get_elb_config"](name, region, key, keyid, profile) if not lb: ret["comment"] = "{} ELB configuration could not be retrieved.".format(name) ret["result"] = False return ret if not security_groups: security_groups = [] change_needed = False if set(security_groups) != set(lb["security_groups"]): change_needed = True if change_needed: if __opts__["test"]: ret["comment"] = "ELB {} set to have security groups modified.".format(name) ret["result"] = None return ret changed = __salt__["boto_elb.apply_security_groups"]( name, security_groups, region, key, keyid, profile ) if changed: ret["comment"] = "Modified security_groups on {} ELB.".format(name) else: ret["comment"] = "Failed to modify security_groups on {} ELB.".format(name) ret["result"] = False ret["changes"]["old"] = {"security_groups": lb["security_groups"]} ret["changes"]["new"] = {"security_groups": security_groups} else: ret["comment"] = "security_groups already set on ELB {}.".format(name) return ret def _attributes_present(name, attributes, region, key, keyid, profile): ret = {"result": True, "comment": "", "changes": {}} _attributes = __salt__["boto_elb.get_attributes"](name, region, key, keyid, profile) if not _attributes: ret["result"] = False ret["comment"] = "Failed to retrieve attributes for ELB {}.".format(name) return ret attrs_to_set = [] if "cross_zone_load_balancing" in attributes: czlb = attributes["cross_zone_load_balancing"] _czlb = _attributes["cross_zone_load_balancing"] if czlb["enabled"] != _czlb["enabled"]: attrs_to_set.append("cross_zone_load_balancing") if "connection_draining" in attributes: cd = attributes["connection_draining"] _cd = _attributes["connection_draining"] if cd["enabled"] != _cd["enabled"] or cd.get("timeout", 300) != _cd.get( "timeout" ): attrs_to_set.append("connection_draining") if "connecting_settings" in attributes: cs = attributes["connecting_settings"] _cs = _attributes["connecting_settings"] if cs["idle_timeout"] != _cs["idle_timeout"]: attrs_to_set.append("connecting_settings") if "access_log" in attributes: for attr, val in attributes["access_log"].items(): if str(_attributes["access_log"][attr]) != str(val): attrs_to_set.append("access_log") if "s3_bucket_prefix" in attributes["access_log"]: sbp = attributes["access_log"]["s3_bucket_prefix"] if sbp.startswith("/") or sbp.endswith("/"): raise SaltInvocationError( "s3_bucket_prefix can not start or end with /." ) if attrs_to_set: if __opts__["test"]: ret["comment"] = "ELB {} set to have attributes set.".format(name) ret["result"] = None return ret was_set = __salt__["boto_elb.set_attributes"]( name, attributes, region, key, keyid, profile ) if was_set: ret["changes"]["old"] = {"attributes": _attributes} ret["changes"]["new"] = {"attributes": attributes} ret["comment"] = "Set attributes on ELB {}.".format(name) else: ret["result"] = False ret["comment"] = "Failed to set attributes on ELB {}.".format(name) else: ret["comment"] = "Attributes already set on ELB {}.".format(name) return ret def _health_check_present(name, health_check, region, key, keyid, profile): ret = {"result": True, "comment": "", "changes": {}} if not health_check: health_check = {} _health_check = __salt__["boto_elb.get_health_check"]( name, region, key, keyid, profile ) if not _health_check: ret["result"] = False ret["comment"] = "Failed to retrieve health_check for ELB {}.".format(name) return ret need_to_set = False for attr, val in health_check.items(): if str(_health_check[attr]) != str(val): need_to_set = True if need_to_set: if __opts__["test"]: ret["comment"] = "ELB {} set to have health check set.".format(name) ret["result"] = None return ret was_set = __salt__["boto_elb.set_health_check"]( name, health_check, region, key, keyid, profile ) if was_set: ret["changes"]["old"] = {"health_check": _health_check} _health_check = __salt__["boto_elb.get_health_check"]( name, region, key, keyid, profile ) ret["changes"]["new"] = {"health_check": _health_check} ret["comment"] = "Set health check on ELB {}.".format(name) else: ret["result"] = False ret["comment"] = "Failed to set health check on ELB {}.".format(name) else: ret["comment"] = "Health check already set on ELB {}.".format(name) return ret def _zones_present(name, availability_zones, region, key, keyid, profile): ret = {"result": True, "comment": "", "changes": {}} lb = __salt__["boto_elb.get_elb_config"](name, region, key, keyid, profile) if not lb: ret["result"] = False ret["comment"] = "Failed to retrieve ELB {}.".format(name) return ret to_enable = [] to_disable = [] _zones = lb["availability_zones"] for zone in availability_zones: if zone not in _zones: to_enable.append(zone) for zone in _zones: if zone not in availability_zones: to_disable.append(zone) if to_enable or to_disable: if __opts__["test"]: ret["comment"] = "ELB {} to have availability zones set.".format(name) ret["result"] = None return ret if to_enable: enabled = __salt__["boto_elb.enable_availability_zones"]( name, to_enable, region, key, keyid, profile ) if enabled: ret["comment"] = "Enabled availability zones on {} ELB.".format(name) else: ret[ "comment" ] = "Failed to enable availability zones on {} ELB.".format(name) ret["result"] = False if to_disable: disabled = __salt__["boto_elb.disable_availability_zones"]( name, to_disable, region, key, keyid, profile ) if disabled: msg = "Disabled availability zones on {0} ELB." ret["comment"] = " ".join([ret["comment"], msg.format(name)]) else: msg = "Failed to disable availability zones on {0} ELB." ret["comment"] = " ".join([ret["comment"], msg.format(name)]) ret["result"] = False ret["changes"]["old"] = {"availability_zones": lb["availability_zones"]} lb = __salt__["boto_elb.get_elb_config"](name, region, key, keyid, profile) ret["changes"]["new"] = {"availability_zones": lb["availability_zones"]} else: ret["comment"] = "Availability zones already set on ELB {}.".format(name) return ret def _subnets_present(name, subnets, region, key, keyid, profile): ret = {"result": True, "comment": "", "changes": {}} if not subnets: subnets = [] lb = __salt__["boto_elb.get_elb_config"](name, region, key, keyid, profile) if not lb: ret["result"] = False ret["comment"] = "Failed to retrieve ELB {}.".format(name) return ret to_enable = [] to_disable = [] _subnets = lb["subnets"] for subnet in subnets: if subnet not in _subnets: to_enable.append(subnet) for subnet in _subnets: if subnet not in subnets: to_disable.append(subnet) if to_enable or to_disable: if __opts__["test"]: ret["comment"] = "ELB {} to have subnets set.".format(name) ret["result"] = None return ret if to_enable: attached = __salt__["boto_elb.attach_subnets"]( name, to_enable, region, key, keyid, profile ) if attached: ret["comment"] = "Attached subnets on {} ELB.".format(name) else: ret["comment"] = "Failed to attach subnets on {} ELB.".format(name) ret["result"] = False if to_disable: detached = __salt__["boto_elb.detach_subnets"]( name, to_disable, region, key, keyid, profile ) if detached: ret["comment"] = " ".join( [ret["comment"], "Detached subnets on {} ELB.".format(name)] ) else: ret["comment"] = " ".join( [ ret["comment"], "Failed to detach subnets on {} ELB.".format(name), ] ) ret["result"] = False ret["changes"]["old"] = {"subnets": lb["subnets"]} lb = __salt__["boto_elb.get_elb_config"](name, region, key, keyid, profile) ret["changes"]["new"] = {"subnets": lb["subnets"]} else: ret["comment"] = "Subnets already set on ELB {}.".format(name) return ret def _alarms_present(name, alarms, alarms_from_pillar, region, key, keyid, profile): """helper method for present. ensure that cloudwatch_alarms are set""" current = __salt__["config.option"](alarms_from_pillar, {}) if alarms: current = salt.utils.dictupdate.update(current, alarms) ret = {"name": name, "result": True, "comment": "", "changes": {}} for _, info in current.items(): info["name"] = name + " " + info["name"] info["attributes"]["description"] = ( name + " " + info["attributes"]["description"] ) info["attributes"]["dimensions"] = {"LoadBalancerName": [name]} kwargs = { "name": info["name"], "attributes": info["attributes"], "region": region, "key": key, "keyid": keyid, "profile": profile, } # No test=False cluase needed since the state handles that itself... results = __states__["boto_cloudwatch_alarm.present"](**kwargs) if not results.get("result"): ret["result"] = results["result"] if results.get("changes", {}) != {}: ret["changes"][info["name"]] = results["changes"] if "comment" in results: ret["comment"] += results["comment"] return ret def _policies_present( name, policies, policies_from_pillar, listeners, backends, region, key, keyid, profile, ): """helper method for present. ensure that ELB policies are set""" if policies is None: policies = [] pillar_policies = __salt__["config.option"](policies_from_pillar, []) policies = policies + pillar_policies if backends is None: backends = [] # check for policy name uniqueness and correct type policy_names = set() for p in policies: if "policy_name" not in p: raise SaltInvocationError("policy_name is a required value for policies.") if "policy_type" not in p: raise SaltInvocationError("policy_type is a required value for policies.") if "policy" not in p: raise SaltInvocationError("policy is a required value for listeners.") # check for unique policy names if p["policy_name"] in policy_names: raise SaltInvocationError( "Policy names must be unique: policy {} is declared twice.".format( p["policy_name"] ) ) policy_names.add(p["policy_name"]) # check that listeners refer to valid policy names for l in listeners: for p in l.get("policies", []): if p not in policy_names: raise SaltInvocationError( "Listener {} on ELB {} refers to undefined policy {}.".format( l["elb_port"], name, p ) ) # check that backends refer to valid policy names for b in backends: for p in b.get("policies", []): if p not in policy_names: raise SaltInvocationError( "Backend {} on ELB {} refers to undefined policy {}.".format( b["instance_port"], name, p ) ) ret = {"result": True, "comment": "", "changes": {}} lb = __salt__["boto_elb.get_elb_config"](name, region, key, keyid, profile) if not lb: ret["comment"] = "{} ELB configuration could not be retrieved.".format(name) ret["result"] = False return ret # Policies have two names: # - a short name ('name') that's only the policy name (e.g. testpolicy) # - a canonical name ('cname') that contains the policy type and hash # (e.g. SSLNegotiationPolicy-testpolicy-14b32f668639cc8ea1391e062af98524) policies_by_cname = {} cnames_by_name = {} for p in policies: cname = _policy_cname(p) policies_by_cname[cname] = p cnames_by_name[p["policy_name"]] = cname expected_policy_names = policies_by_cname.keys() actual_policy_names = lb["policies"] # This is sadly a huge hack to get around the fact that AWS assigns a # default SSLNegotiationPolicyType policy (with the naming scheme # ELBSecurityPolicy-YYYY-MM) to all ELBs terminating SSL without an # explicit policy set. If we don't keep track of the default policies and # explicitly exclude them from deletion, orchestration will fail because we # attempt to delete the default policy that's being used by listeners that # were created with no explicit policy. default_aws_policies = set() expected_policies_by_listener = {} for l in listeners: expected_policies_by_listener[l["elb_port"]] = { cnames_by_name[p] for p in l.get("policies", []) } actual_policies_by_listener = {} for l in lb["listeners"]: listener_policies = set(l.get("policies", [])) actual_policies_by_listener[l["elb_port"]] = listener_policies # Determine if any actual listener policies look like default policies, # so we can exclude them from deletion below (see note about this hack # above). for p in listener_policies: if re.match(r"^ELBSecurityPolicy-\d{4}-\d{2}$", p): default_aws_policies.add(p) expected_policies_by_backend = {} for b in backends: expected_policies_by_backend[b["instance_port"]] = { cnames_by_name[p] for p in b.get("policies", []) } actual_policies_by_backend = {} for b in lb["backends"]: backend_policies = set(b.get("policies", [])) actual_policies_by_backend[b["instance_port"]] = backend_policies to_delete = [] to_create = [] for policy_name in expected_policy_names: if policy_name not in actual_policy_names: to_create.append(policy_name) for policy_name in actual_policy_names: if policy_name not in expected_policy_names: if policy_name not in default_aws_policies: to_delete.append(policy_name) listeners_to_update = set() for port, policies in expected_policies_by_listener.items(): if policies != actual_policies_by_listener.get(port, set()): listeners_to_update.add(port) for port, policies in actual_policies_by_listener.items(): if policies != expected_policies_by_listener.get(port, set()): listeners_to_update.add(port) backends_to_update = set() for port, policies in expected_policies_by_backend.items(): if policies != actual_policies_by_backend.get(port, set()): backends_to_update.add(port) for port, policies in actual_policies_by_backend.items(): if policies != expected_policies_by_backend.get(port, set()): backends_to_update.add(port) if __opts__["test"]: msg = [] if to_create or to_delete: msg.append("ELB {} set to have policies modified:".format(name)) for policy in to_create: msg.append("Policy {} added.".format(policy)) for policy in to_delete: msg.append("Policy {} deleted.".format(policy)) ret["result"] = None else: msg.append("Policies already set on ELB {}.".format(name)) for listener in listeners_to_update: msg.append("Listener {} policies updated.".format(listener)) for backend in backends_to_update: msg.append("Backend {} policies updated.".format(backend)) ret["comment"] = " ".join(msg) return ret if to_create: for policy_name in to_create: created = __salt__["boto_elb.create_policy"]( name=name, policy_name=policy_name, policy_type=policies_by_cname[policy_name]["policy_type"], policy=policies_by_cname[policy_name]["policy"], region=region, key=key, keyid=keyid, profile=profile, ) if created: ret["changes"].setdefault(policy_name, {})["new"] = policy_name comment = "Policy {} was created on ELB {}".format(policy_name, name) ret["comment"] = " ".join([ret["comment"], comment]) ret["result"] = True else: ret["result"] = False return ret for port in listeners_to_update: policy_set = __salt__["boto_elb.set_listener_policy"]( name=name, port=port, policies=list(expected_policies_by_listener.get(port, [])), region=region, key=key, keyid=keyid, profile=profile, ) if policy_set: policy_key = "listener_{}_policy".format(port) ret["changes"][policy_key] = { "old": list(actual_policies_by_listener.get(port, [])), "new": list(expected_policies_by_listener.get(port, [])), } comment = "Policy {} was created on ELB {} listener {}".format( expected_policies_by_listener[port], name, port ) ret["comment"] = " ".join([ret["comment"], comment]) ret["result"] = True else: ret["result"] = False return ret for port in backends_to_update: policy_set = __salt__["boto_elb.set_backend_policy"]( name=name, port=port, policies=list(expected_policies_by_backend.get(port, [])), region=region, key=key, keyid=keyid, profile=profile, ) if policy_set: policy_key = "backend_{}_policy".format(port) ret["changes"][policy_key] = { "old": list(actual_policies_by_backend.get(port, [])), "new": list(expected_policies_by_backend.get(port, [])), } comment = "Policy {} was created on ELB {} backend {}".format( expected_policies_by_backend[port], name, port ) ret["comment"] = " ".join([ret["comment"], comment]) ret["result"] = True else: ret["result"] = False return ret if to_delete: for policy_name in to_delete: deleted = __salt__["boto_elb.delete_policy"]( name=name, policy_name=policy_name, region=region, key=key, keyid=keyid, profile=profile, ) if deleted: ret["changes"].setdefault(policy_name, {})["old"] = policy_name comment = "Policy {} was deleted from ELB {}".format(policy_name, name) ret["comment"] = " ".join([ret["comment"], comment]) ret["result"] = True else: ret["result"] = False return ret return ret def _policy_cname(policy_dict): policy_name = policy_dict["policy_name"] policy_type = policy_dict["policy_type"] policy = policy_dict["policy"] canonical_policy_repr = str(sorted(list(policy.items()), key=lambda x: str(x[0]))) policy_hash = hashlib.md5( salt.utils.stringutils.to_bytes(str(canonical_policy_repr)) ).hexdigest() if policy_type.endswith("Type"): policy_type = policy_type[:-4] return "{}-{}-{}".format(policy_type, policy_name, policy_hash) def absent(name, region=None, key=None, keyid=None, profile=None): """ Ensure an ELB does not exist name name of the ELB """ ret = {"name": name, "result": True, "comment": "", "changes": {}} exists = __salt__["boto_elb.exists"](name, region, key, keyid, profile) if exists: if __opts__["test"]: ret["comment"] = "ELB {} is set to be removed.".format(name) ret["result"] = None return ret deleted = __salt__["boto_elb.delete"](name, region, key, keyid, profile) if deleted: ret["changes"]["old"] = {"elb": name} ret["changes"]["new"] = {"elb": None} ret["comment"] = "ELB {} deleted.".format(name) else: ret["result"] = False ret["comment"] = "Failed to delete {} ELB.".format(name) else: ret["comment"] = "{} ELB does not exist.".format(name) return ret def _tags_present(name, tags, region, key, keyid, profile): """ helper function to validate tags on elb """ ret = {"result": True, "comment": "", "changes": {}} if tags: lb = __salt__["boto_elb.get_elb_config"](name, region, key, keyid, profile) tags_to_add = tags tags_to_update = {} tags_to_remove = [] if lb.get("tags"): for _tag in lb["tags"]: if _tag not in tags.keys(): if _tag not in tags_to_remove: tags_to_remove.append(_tag) else: if tags[_tag] != lb["tags"][_tag]: tags_to_update[_tag] = tags[_tag] tags_to_add.pop(_tag) if tags_to_remove: if __opts__["test"]: msg = "The following tag{} set to be removed: {}.".format( ("s are" if len(tags_to_remove) > 1 else " is"), ", ".join(tags_to_remove), ) ret["comment"] = " ".join([ret["comment"], msg]) ret["result"] = None else: _ret = __salt__["boto_elb.delete_tags"]( name, tags_to_remove, region, key, keyid, profile ) if not _ret: ret["result"] = False msg = "Error attempting to delete tag {}.".format(tags_to_remove) ret["comment"] = " ".join([ret["comment"], msg]) return ret if "old" not in ret["changes"]: ret["changes"] = salt.utils.dictupdate.update( ret["changes"], {"old": {"tags": {}}} ) for _tag in tags_to_remove: ret["changes"]["old"]["tags"][_tag] = lb["tags"][_tag] if tags_to_add or tags_to_update: if __opts__["test"]: if tags_to_add: msg = "The following tag{} set to be added: {}.".format( ("s are" if len(tags_to_add.keys()) > 1 else " is"), ", ".join(tags_to_add.keys()), ) ret["comment"] = " ".join([ret["comment"], msg]) ret["result"] = None if tags_to_update: msg = "The following tag {} set to be updated: {}.".format( ( "values are" if len(tags_to_update.keys()) > 1 else "value is" ), ", ".join(tags_to_update.keys()), ) ret["comment"] = " ".join([ret["comment"], msg]) else: all_tag_changes = salt.utils.dictupdate.update( tags_to_add, tags_to_update ) _ret = __salt__["boto_elb.set_tags"]( name, all_tag_changes, region, key, keyid, profile ) if not _ret: ret["result"] = False msg = "Error attempting to set tags." ret["comment"] = " ".join([ret["comment"], msg]) return ret if "old" not in ret["changes"]: ret["changes"] = salt.utils.dictupdate.update( ret["changes"], {"old": {"tags": {}}} ) if "new" not in ret["changes"]: ret["changes"] = salt.utils.dictupdate.update( ret["changes"], {"new": {"tags": {}}} ) for tag in all_tag_changes: ret["changes"]["new"]["tags"][tag] = tags[tag] if "tags" in lb: if lb["tags"]: if tag in lb["tags"]: ret["changes"]["old"]["tags"][tag] = lb["tags"][tag] if not tags_to_update and not tags_to_remove and not tags_to_add: msg = "Tags are already set." ret["comment"] = " ".join([ret["comment"], msg]) return ret
Save