Merge "Updated absent and role_unassign states behavior." into release/2019.2.0
diff --git a/keystone/client/resources/v3.sls b/keystone/client/resources/v3.sls
index b91ad6d..7803233 100644
--- a/keystone/client/resources/v3.sls
+++ b/keystone/client/resources/v3.sls
@@ -4,27 +4,35 @@
 {%- if resources.get('enabled', False) %}
 
 {% for role_name,role  in resources.get('roles', {}).iteritems() %}
+  {%- if role.enabled %}
 
-{%- if role.enabled %}
+    {%- if role.get('status', 'present') == 'present' %}
+
 keystone_role_{{ role_name }}:
   keystonev3.role_present:
     - cloud_name: {{ role.get('cloud_name', resources.cloud_name) }}
-    {#- The role name is not uniq among domains, use name here to have ability create #}
-    {#- roles with the same name in different domains #}
+      {#- The role name is not uniq among domains, use name here to have ability create #}
+      {#- roles with the same name in different domains #}
     - name: {{ role.name }}
-    {%- if role.domain_id is defined %}
+      {%- if role.domain_id is defined %}
     - domain_id: {{ role.domain_id }}
-    {%- endif %}
-{%- else %}
+      {%- endif %}
+
+    {%- elif role.get('status', 'present') == 'absent' %}
+
 keystone_role_{{ role_name }}:
   keystonev3.role_absent:
     - cloud_name: {{ role.get('cloud_name', resources.cloud_name) }}
     - name: {{ role_name }}
-{%- endif %}
 
+    {%- endif %}
+
+  {%- endif %}
 {%- endfor %}
 
-{% for service_name,service  in resources.get('services', {}).iteritems() %}
+{%- for service_name,service  in resources.get('services', {}).iteritems() %}
+  {%- if service.get('status', 'present') == 'present' %}
+
 keystone_service_{{ service_name }}_{{ service.type }}:
   keystonev3.service_present:
     - cloud_name: {{ service.get('cloud_name', resources.cloud_name) }}
@@ -37,23 +45,45 @@
     - enabled: {{ service.enabled }}
     {%- endif %}
 
-    {% for endpoint_name, endpoint  in service.get('endpoints', {}).iteritems() %}
+  {%- elif service.get('status', 'present') == 'absent' %}
+
+keystone_service_{{ service_name }}_{{ service.type }}_absent:
+  keystonev3.service_absent:
+    - cloud_name: {{ service.get('cloud_name', resources.cloud_name) }}
+    - name: {{ service_name }}
+
+  {%- endif %}
+
+  {%- for endpoint_name, endpoint  in service.get('endpoints', {}).iteritems() %}
+    {%- if endpoint.get('status', 'present') == 'present' %}
 
 keystone_endpoint_{{ endpoint_name }}_{{ endpoint.interface }}_{{ endpoint.region }}:
   keystonev3.endpoint_present:
-  - name: {{ endpoint_name }}
-  - cloud_name: {{ endpoint.get('cloud_name', resources.cloud_name) }}
-  - url: {{ endpoint.url }}
-  - interface: {{ endpoint.interface }}
-  - service_id: {{ service_name }}
-  - region_id: {{ endpoint.region }}
-  - require:
-    - keystone_service_{{ service_name }}_{{ service.type }}
+    - name: {{ endpoint_name }}
+    - cloud_name: {{ endpoint.get('cloud_name', resources.cloud_name) }}
+    - url: {{ endpoint.url }}
+    - interface: {{ endpoint.interface }}
+    - service_id: {{ service_name }}
+    - region_id: {{ endpoint.region }}
+    - require:
+      - keystone_service_{{ service_name }}_{{ service.type }}
 
-    {%- endfor %}
-{% endfor %}
+    {%- elif endpoint.get('status', 'present') == 'absent' %}
+
+keystone_endpoint_{{ endpoint_name }}_{{ endpoint.interface }}_{{ endpoint.region }}_absent:
+  keystonev3.endpoint_absent:
+    - name: {{ endpoint_name }}
+    - cloud_name: {{ endpoint.get('cloud_name', resources.cloud_name) }}
+    - interface: {{ endpoint.interface }}
+    - service_id: {{ service_name }}
+
+    {%- endif %}
+  {%- endfor %}
+
+{%- endfor %}
 
 {% for domain_name, domain  in resources.get('domains', {}).iteritems() %}
+  {%- if domain.get('status', 'present') == 'present' %}
 
 keystone_domain_{{ domain_name }}:
   keystonev3.domain_present:
@@ -69,73 +99,126 @@
     - tags: {{ domain.tags }}
     {%- endif %}
 
-    {%- for project_name, project in domain.get('projects', {}).iteritems() %}
-keystone_project_{{ project_name }}:
-  keystonev3.project_present:
-  - cloud_name: {{ project.get('cloud_name', resources.cloud_name) }}
-  - name: {{ project_name }}
-  - domain_id: {{ project.get('domain_id', 'default')}}
-  {%- if project.is_domain is defined %}
-  - is_domain: {{ project.is_domain }}
-  {%- endif %}
-  {%- if project.description is defined %}
-  - description: {{ project.description }}
-  {%- endif %}
-  {%- if project.enabled is defined %}
-  - enabled: {{ project.enabled }}
-  {%- endif %}
-  {%- if project.parent_id is defined %}
-  - parent_id: {{ project.parent_id }}
-  {%- endif %}
-  {%- if project.tags is defined %}
-  - tags: {{ project.tags }}
+  {%- elif domain.get('status', 'present') == 'absent' %}
+
+keystone_domain_{{ domain_name }}_absent:
+  keystonev3.domain_absent:
+    - name: {{ domain_name }}
+    - cloud_name: {{ domain.get('cloud_name', resources.cloud_name) }}
+    {%- if domain.force_delete is defined %}
+    - force_delete: {{ domain.force_delete }}
+    {%- endif %}
+
   {%- endif %}
 
-    {%- endfor %}
+  {%- for project_name, project in domain.get('projects', {}).iteritems() %}
+    {%- if project.get('status', 'present') == 'present' %}
+
+keystone_project_{{ project_name }}:
+  keystonev3.project_present:
+    - cloud_name: {{ project.get('cloud_name', resources.cloud_name) }}
+    - name: {{ project_name }}
+    - domain_id: {{ project.get('domain_id', 'default')}}
+      {%- if project.is_domain is defined %}
+    - is_domain: {{ project.is_domain }}
+      {%- endif %}
+      {%- if project.description is defined %}
+    - description: {{ project.description }}
+      {%- endif %}
+      {%- if project.enabled is defined %}
+    - enabled: {{ project.enabled }}
+      {%- endif %}
+      {%- if project.parent_id is defined %}
+    - parent_id: {{ project.parent_id }}
+      {%- endif %}
+      {%- if project.tags is defined %}
+    - tags: {{ project.tags }}
+      {%- endif %}
+
+    {%- elif project.get('status', 'present') == 'absent' %}
+
+keystone_project_{{ project_name }}_absent:
+  keystonev3.project_absent:
+    - cloud_name: {{ project.get('cloud_name', resources.cloud_name) }}
+    - name: {{ project_name }}
+
+    {%- endif %}
+  {%- endfor %}
 
 {%- endfor %}
 
 {%- for user_name, user in resources.get('users', {}).iteritems() %}
+  {%- if user.get('status', 'present') == 'present' %}
 
 keystone_user_{{ user_name }}:
   keystonev3.user_present:
-  - cloud_name: {{ user.get('cloud_name', resources.cloud_name) }}
-  - name: {{ user_name }}
-  {%- if user.default_project_id is defined %}
-  - default_project_id: {{ user.default_project_id }}
-  {%- endif %}
-  {%- if user.domain_id is defined %}
-  - domain_id: {{ user.domain_id }}
-  {%- endif %}
-  {%- if user.enabled is defined %}
-  - enabled: {{ user.enabled }}
-  {%- endif %}
-  {%- if user.password is defined %}
-  - password: {{ user.password }}
-  {%- endif %}
-  {%- if user.email is defined %}
-  - email: {{ user.email }}
-  {%- endif %}
-  {%- if user.password_reset is defined %}
-  - password_reset: {{ user.password_reset }}
+    - cloud_name: {{ user.get('cloud_name', resources.cloud_name) }}
+    - name: {{ user_name }}
+    {%- if user.default_project_id is defined %}
+    - default_project_id: {{ user.default_project_id }}
+    {%- endif %}
+    {%- if user.domain_id is defined %}
+    - domain_id: {{ user.domain_id }}
+    {%- endif %}
+    {%- if user.enabled is defined %}
+    - enabled: {{ user.enabled }}
+    {%- endif %}
+    {%- if user.password is defined %}
+    - password: {{ user.password }}
+    {%- endif %}
+    {%- if user.email is defined %}
+    - email: {{ user.email }}
+    {%- endif %}
+    {%- if user.password_reset is defined %}
+    - password_reset: {{ user.password_reset }}
+    {%- endif %}
+
+  {%- elif user.get('status', 'present') == 'absent' %}
+
+keystone_user_{{ user_name }}_absent:
+  keystonev3.user_absent:
+    - cloud_name: {{ user.get('cloud_name', resources.cloud_name) }}
+    - name: {{ user_name }}
+
   {%- endif %}
 
-    {%- for role_name,role in user.get('roles', {}).iteritems() %}
+  {%- for role_name,role in user.get('roles', {}).iteritems() %}
+    {%- if role.get('status', 'assigned') == 'assigned' %}
+
 keystone_user_{{ user_name }}_role_{{ role.name }}_assigned:
   keystonev3.user_role_assigned:
     - name: {{ user_name }}
     - role_id: {{ role.name }}
     - cloud_name: {{ user.get('cloud_name', resources.cloud_name) }}
-    {%- if role.domain_id is defined %}
+      {%- if role.domain_id is defined %}
     - domain_id: {{ role.domain_id }}
-    {%- endif %}
-    {%- if role.project_id is defined %}
+      {%- endif %}
+      {%- if role.project_id is defined %}
     - project_id: {{ role.project_id }}
-    {%- endif %}
-    {%- if role.role_domain_id is defined %}
+      {%- endif %}
+      {%- if role.role_domain_id is defined %}
     - role_domain_id: {{ role.role_domain_id }}
+      {%- endif %}
+
+    {%- elif role.get('status', 'assigned') == 'unassigned' %}
+
+keystone_user_{{ user_name }}_role_{{ role.name }}_unassign:
+  keystonev3.user_role_unassign:
+    - name: {{ user_name }}
+    - role_id: {{ role.name }}
+    - cloud_name: {{ user.get('cloud_name', resources.cloud_name) }}
+      {%- if role.domain_id is defined %}
+    - domain_id: {{ role.domain_id }}
+      {%- endif %}
+      {%- if role.project_id is defined %}
+    - project_id: {{ role.project_id }}
+      {%- endif %}
+      {%- if role.role_domain_id is defined %}
+    - role_domain_id: {{ role.role_domain_id }}
+      {%- endif %}
+
     {%- endif %}
-    {%- endfor %}
+  {%- endfor %}
 
 {%- endfor %}
 
diff --git a/keystone/client/server.sls b/keystone/client/server.sls
index ef78a5f..e470585 100644
--- a/keystone/client/server.sls
+++ b/keystone/client/server.sls
@@ -62,6 +62,7 @@
   {%- endif %}
 
 {%- for endpoint in service.get('endpoints', ()) %}
+  {%- if endpoint.get('status', 'present') == 'present' %}
 
 keystone_{{ server_name }}_service_{{ service_name }}_endpoint_{{ endpoint.region }}:
   keystoneng.endpoint_present:
@@ -72,14 +73,23 @@
   - region: {{ endpoint.region }}
   - require:
     - keystoneng: keystone_{{ server_name }}_service_{{ service_name }}
-  {%- if server.admin.token is defined %}
+    {%- if server.admin.token is defined %}
   - connection_token: {{ connection_args.token }}
   - connection_endpoint: {{ connection_args.endpoint }}
-  {%- else %}
+    {%- else %}
   - connection_user: {{ connection_args.user }}
   - connection_password: {{ connection_args.password }}
   - connection_tenant: {{ connection_args.tenant }}
   - connection_auth_url: {{ connection_args.auth_url }}
+    {%- endif %}
+
+  {%- elif endpoint.get('status', 'present') == 'absent' %}
+
+keystone_{{ server_name }}_service_{{ service_name }}_endpoint_{{ endpoint.region }}_absent:
+  keystoneng.endpoint_absent:
+    - name: {{ service_name }}
+    - region: {{ endpoint.region }}
+
   {%- endif %}
 
 {%- endfor %}
diff --git a/tests/pillar/client_resources_v3.sls b/tests/pillar/client_resources_v3.sls
new file mode 100644
index 0000000..f68ef70
--- /dev/null
+++ b/tests/pillar/client_resources_v3.sls
@@ -0,0 +1,145 @@
+include:
+  - single
+
+keystone:
+  client:
+    resources:
+      v3:
+        enabled: true
+        cloud_name: 'admin_identity'
+        domains:
+          'Default':
+            enabled: True
+            status: present
+            projects:
+              service:
+                status: present
+                description: "OpenStack Service tenant"
+              admin:
+                status: absent
+                description: "OpenStack Admin tenant"
+          'User_domain':
+            enabled: True
+            status: absent
+            projects:
+              user_domain_service:
+                status: present
+                description: "OpenStack Service tenant"
+              user_domain_admin:
+                status: absent
+                description: "OpenStack Admin tenant"
+          'User_domain_0':
+            enabled: True
+            status: absent
+            force_delete: True
+            projects:
+              user_domain_0_service:
+                status: present
+                description: "OpenStack Service tenant"
+              user_domain_0_admin:
+                status: absent
+                description: "OpenStack Admin tenant"
+          'User_domain_1':
+            enabled: False
+            status: absent
+            projects:
+              user_domain_1_service:
+                status: present
+                description: "OpenStack Service tenant"
+              user_domain_1_admin:
+                status: absent
+                description: "OpenStack Admin tenant"
+        roles:
+          service_admin:
+            name: admin
+            enabled: true
+            status: present
+          global_Member:
+            name: Member
+            enabled: true
+            status: absent
+          global_Member_0:
+            name: Member
+            enabled: False
+            status: absent
+        users:
+          admin:
+            enabled: true
+            status: present
+            password: passw0rd
+            email: root@localhost
+            roles:
+              service_admin:
+                status: assigned
+                name: admin
+                project_id: admin
+          user:
+            enabled: true
+            status: absent
+            password: passw0rd
+            email: root@localhost
+            roles:
+              global_Member:
+                status: unassigned
+                name: user
+                project_id: user
+          user0:
+            enabled: False
+            status: absent
+            password: passw0rd
+            email: root@localhost
+            roles:
+              global_Member:
+                status: unassigned
+                name: user
+                project_id: user
+        services:
+          keystone:
+            enabled: True
+            status: present
+            type: 'identity'
+            description: "OpenStack Identity Service"
+            endpoints:
+              keystone_public:
+                status: present
+                interface: 'public'
+                url: https://127.0.0.1:5000/
+                region: RegionOne
+              keystone_internal:
+                status: absent
+                interface: 'internal'
+                url: https://127.0.0.1:5000/
+                region: RegionOne
+          keystone_0:
+            enabled: True
+            status: absent
+            type: 'identity'
+            description: "OpenStack Identity Service"
+            endpoints:
+              keystone_0_public:
+                status: present
+                interface: 'public'
+                url: https://127.0.0.1:5000/
+                region: RegionOne
+              keystone_0_internal:
+                status: absent
+                interface: 'internal'
+                url: https://127.0.0.1:5000/
+                region: RegionOne
+          keystone_1:
+            enabled: False
+            status: absent
+            type: 'identity'
+            description: "OpenStack Identity Service"
+            endpoints:
+              keystone_1_public:
+                status: present
+                interface: 'public'
+                url: https://127.0.0.1:5000/
+                region: RegionOne
+              keystone_1_internal:
+                status: absent
+                interface: 'internal'
+                url: https://127.0.0.1:5000/
+                region: RegionOne
+