Repository: ansible/ansible
Pull request: elb_application_lb purge rules option
##### SUMMARY
Adds the ability to leave existing rules in place on an ELB.
Fixes #43109

##### ISSUE TYPE
 - Bugfix Pull Request

##### COMPONENT NAME
elb_application_lb

##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes below -->
```
ansible 2.7.0.dev0 (detached HEAD f6160c675d) last updated 2018/07/20 18:28:16 (GMT +000)
  config file = /home/vagrant/.ansible.cfg
  configured module search path = [u'/home/vagrant/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /home/vagrant/ansible/lib/ansible
  executable location = /home/vagrant/ansible/bin/ansible
  python version = 2.7.15 (default, May  9 2018, 11:32:33) [GCC 7.3.1 20180130 (Red Hat 7.3.1-2)]
```



Problem statement:
elb_application_lb cannot append rules only create/replace
<!---
Verify first that your issue/request is not already reported on GitHub.
THIS FORM WILL BE READ BY A MACHINE, COMPLETE ALL SECTIONS AS DESCRIBED.
Also test if the latest release, and devel branch are affected too.
ALWAYS add information AFTER (OUTSIDE) these html comments.
Otherwise it may end up being automatically closed by our bot. -->

##### SUMMARY
elb_application_lb module does not allow for the modification of rules without replacing existing rules.

##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
elb_application_lb

##### ANSIBLE VERSION
```
ansible 2.7.0.dev0 (detached HEAD f6160c675d) last updated 2018/07/20 18:28:16 (GMT +000)
  config file = /home/vagrant/.ansible.cfg
  configured module search path = [u'/home/vagrant/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /home/vagrant/ansible/lib/ansible
  executable location = /home/vagrant/ansible/bin/ansible
  python version = 2.7.15 (default, May  9 2018, 11:32:33) [GCC 7.3.1 20180130 (Red Hat 7.3.1-2)]
```

##### CONFIGURATION
DEFAULT_LOG_PATH(/home/vagrant/.ansible.cfg) = /home/vagrant/ansible.log

##### OS / ENVIRONMENT
N/A

##### STEPS TO REPRODUCE
Create an elb with rules then attempt to modify those rules. All rules that are not specified in the new task will be purged.


```yaml
  - name: add a rule to the listener
    elb_application_lb:
      name: "{{ alb_name }}"
      subnets: "{{ alb_subnets }}"
      security_groups: "{{ sec_group.group_id }}"
      state: present
      listeners:
        - Protocol: HTTP
          Port: 80
          DefaultActions:
            - Type: forward
              TargetGroupName: "{{ tg_name }}"
          Rules:
            - Conditions:
                - Field: path-pattern
                  Values:
                    - '/test'
              Priority: '1'
              Actions:
                - TargetGroupName: "{{ tg_name }}"
                  Type: forward
      <<: *aws_connection_info
    register: alb

  - assert:
      that:
        - alb.changed
        - alb.listeners[0].rules|length == 2

  - name: test a rule can be added and other rules will not be removed
    elb_application_lb:
      name: "{{ alb_name }}"
      subnets: "{{ alb_subnets }}"
      security_groups: "{{ sec_group.group_id }}"
      state: present
      purge_listeners: no
      listeners:
        - Protocol: HTTP
          Port: 80
          DefaultActions:
            - Type: forward
              TargetGroupName: "{{ tg_name }}"
          Rules:
            - Conditions:
                - Field: path-pattern
                  Values:
                    - '/new'
              Priority: '2'
              Actions:
                - TargetGroupName: "{{ tg_name }}"
                  Type: forward
      <<: *aws_connection_info
    register: alb

  - assert:
      that:
        - alb.changed
        - alb.listeners[0].rules|length == 3
```

##### EXPECTED RESULTS
When purge listeners is set to no I expected that the existing listeners and rules would stay in place.
##### ACTUAL RESULTS
Existing rules were purged and replaced.

Hints from issue discussion:
Files identified in the description:
* [lib/ansible/modules/cloud/amazon/elb_application_lb.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/cloud/amazon/elb_application_lb.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @wimnat
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
So here is the scenario where I'm running into issues with the rules being wiped out. I have different ansible roles for each one of my applications. These playbooks don't have any knowledge of the other playbooks and their elb rules. I want to be able to add new rules to an elb without wiping out the existing rules. I have PR #43113 that adds an option to leave the rules in place.

Commit message: Expand purge_rules documentation

Patch to review:
diff --git a/lib/ansible/modules/cloud/amazon/elb_application_lb.py b/lib/ansible/modules/cloud/amazon/elb_application_lb.py
index 3985e9c70b5f64..e8d983e3907eff 100644
--- a/lib/ansible/modules/cloud/amazon/elb_application_lb.py
+++ b/lib/ansible/modules/cloud/amazon/elb_application_lb.py
@@ -119,6 +119,12 @@
     description:
       - The time in seconds to use in conjunction with I(wait).
     version_added: 2.6
+  purge_rules:
+    description:
+      - Keeps the existing load balancer rules in place. Will modify and add, but will not delete.
+    default: yes
+    type: bool
+    version_added: 2.7
 extends_documentation_fragment:
     - aws
     - ec2
@@ -444,10 +450,11 @@ def create_or_update_elb(elb_obj):
             rules_to_add, rules_to_modify, rules_to_delete = rules_obj.compare_rules()
 
             # Delete rules
-            for rule in rules_to_delete:
-                rule_obj = ELBListenerRule(elb_obj.connection, elb_obj.module, {'RuleArn': rule}, rules_obj.listener_arn)
-                rule_obj.delete()
-                elb_obj.changed = True
+            if elb_obj.module.params['purge_rules']:
+                for rule in rules_to_delete:
+                    rule_obj = ELBListenerRule(elb_obj.connection, elb_obj.module, {'RuleArn': rule}, rules_obj.listener_arn)
+                    rule_obj.delete()
+                    elb_obj.changed = True
 
             # Add rules
             for rule in rules_to_add:
@@ -524,7 +531,8 @@ def main():
             state=dict(choices=['present', 'absent'], type='str'),
             tags=dict(type='dict'),
             wait_timeout=dict(type='int'),
-            wait=dict(default=False, type='bool')
+            wait=dict(default=False, type='bool'),
+            purge_rules=dict(default=True, type='bool')
         )
     )
 
diff --git a/test/integration/targets/elb_application_lb/tasks/test_modifying_alb_listeners.yml b/test/integration/targets/elb_application_lb/tasks/test_modifying_alb_listeners.yml
index db05dab29ba729..31c1569168b9c4 100644
--- a/test/integration/targets/elb_application_lb/tasks/test_modifying_alb_listeners.yml
+++ b/test/integration/targets/elb_application_lb/tasks/test_modifying_alb_listeners.yml
@@ -88,6 +88,36 @@
         - not alb.changed
         - alb.listeners[0].rules|length == 2
 
+  - name: test a rule can be added and other rules will not be removed when purge_rules is no.
+    elb_application_lb:
+      name: "{{ alb_name }}"
+      subnets: "{{ alb_subnets }}"
+      security_groups: "{{ sec_group.group_id }}"
+      state: present
+      purge_rules: no
+      listeners:
+        - Protocol: HTTP
+          Port: 80
+          DefaultActions:
+            - Type: forward
+              TargetGroupName: "{{ tg_name }}"
+          Rules:
+            - Conditions:
+                - Field: path-pattern
+                  Values:
+                    - '/new'
+              Priority: '2'
+              Actions:
+                - TargetGroupName: "{{ tg_name }}"
+                  Type: forward
+      <<: *aws_connection_info
+    register: alb
+
+  - assert:
+      that:
+        - alb.changed
+        - alb.listeners[0].rules|length == 3
+
   - name: remove the rule
     elb_application_lb:
       name: "{{ alb_name }}"


Code review comments:
diff_hunk: @@ -119,6 +119,12 @@
     description:
       - The time in seconds to use in conjunction with I(wait).
     version_added: 2.6
+  purge_rules:
+    description:
+      - Keeps the existing load balancer rules in place. Will modify and add, but will not delete.
path: lib/ansible/modules/cloud/amazon/elb_application_lb.py
text: @user1:
This description reads as if setting `purge_rules` to `yes` would keep the existing load balancer rules in place. 

Perhaps just prefix it with 'When set to no, keep the existing...'