mirror of
				https://github.com/kevinveenbirkenbach/computer-playbook.git
				synced 2025-11-03 19:58:14 +00:00 
			
		
		
		
	- Improved get_service_name filter plugin (clearer suffix handling, consistent var names). - Added MODE_ASSERT flag to optionally execute validation/assertion tasks. - Fixed systemd unit handling: consistent use of %I instead of %i, correct escaping of instance names. - Unified on_failure behavior and alarm composer scripts. - Cleaned up redundant logging, handlers, and debug config. - Strengthened sys-service template resolution with assert (only active when MODE_ASSERT). - Simplified timer and suffix handling with get_service_name filter. - Hardened sensitive tasks with no_log. - Added conditional asserts across roles (Keycloak, DNS, Mailu, Discourse, etc.). These changes improve consistency, safety, and validation across the automation stack. Conversation: https://chatgpt.com/share/68a4ae28-483c-800f-b2f7-f64c7124c274
		
			
				
	
	
		
			148 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			YAML
		
	
	
	
	
	
			
		
		
	
	
			148 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			YAML
		
	
	
	
	
	
- name: "Update REALM settings (merge LDAP component .config)"
 | 
						|
  include_tasks: _update.yml
 | 
						|
  vars:
 | 
						|
    kc_object_kind:  "component"
 | 
						|
    kc_lookup_value: "{{ KEYCLOAK_LDAP_CMP_NAME }}"
 | 
						|
    kc_desired: >-
 | 
						|
      {{
 | 
						|
        (
 | 
						|
          KEYCLOAK_DICTIONARY_REALM.components['org.keycloak.storage.UserStorageProvider']
 | 
						|
          | selectattr('name','equalto', KEYCLOAK_LDAP_CMP_NAME)
 | 
						|
          | list | first
 | 
						|
        )
 | 
						|
      }}
 | 
						|
    kc_merge_path: "config"
 | 
						|
 | 
						|
- name: Resolve LDAP component id
 | 
						|
  shell: >
 | 
						|
    {{ KEYCLOAK_EXEC_KCADM }} get components
 | 
						|
    -r {{ KEYCLOAK_REALM }}
 | 
						|
    --query 'name={{ KEYCLOAK_LDAP_CMP_NAME }}'
 | 
						|
    --fields id --format json | jq -r '.[0].id'
 | 
						|
  register: ldap_cmp_id
 | 
						|
  changed_when: false
 | 
						|
 | 
						|
- name: Assert LDAP component id resolved
 | 
						|
  assert:
 | 
						|
    that: [ "(ldap_cmp_id.stdout | trim) not in ['', 'null']" ]
 | 
						|
    fail_msg: "LDAP component '{{ KEYCLOAK_LDAP_CMP_NAME }}' not found in Keycloak."
 | 
						|
  when: MODE_ASSERT | bool
 | 
						|
 | 
						|
- name: Pull LDAP component from dictionary (by name)
 | 
						|
  set_fact:
 | 
						|
    ldap_component_tpl: >-
 | 
						|
      {{
 | 
						|
        KEYCLOAK_DICTIONARY_REALM.components['org.keycloak.storage.UserStorageProvider']
 | 
						|
        | selectattr('name','equalto', KEYCLOAK_LDAP_CMP_NAME)
 | 
						|
        | list | first | default({})
 | 
						|
      }}
 | 
						|
 | 
						|
- name: Sanity check dictionary LDAP component
 | 
						|
  assert:
 | 
						|
    that:
 | 
						|
      - ldap_component_tpl | length > 0
 | 
						|
      - (ldap_component_tpl.subComponents | default({})) | length > 0
 | 
						|
    fail_msg: "LDAP component '{{ KEYCLOAK_LDAP_CMP_NAME }}' not found in KEYCLOAK_DICTIONARY_REALM."
 | 
						|
  when: MODE_ASSERT | bool
 | 
						|
 | 
						|
- name: Extract mapper 'ldap-roles' from template (raw)
 | 
						|
  set_fact:
 | 
						|
    desired_group_mapper_raw: >-
 | 
						|
      {{
 | 
						|
        (
 | 
						|
          ldap_component_tpl.subComponents['org.keycloak.storage.ldap.mappers.LDAPStorageMapper']
 | 
						|
          | default([])
 | 
						|
        )
 | 
						|
        | selectattr('name','equalto','ldap-roles')
 | 
						|
        | list | first | default({})
 | 
						|
      }}
 | 
						|
 | 
						|
- name: Ensure mapper exists in dictionary
 | 
						|
  assert:
 | 
						|
    that: [ "desired_group_mapper_raw | length > 0" ]
 | 
						|
    fail_msg: "'ldap-roles' mapper not found in dictionary under LDAP component."
 | 
						|
  when: MODE_ASSERT | bool
 | 
						|
 | 
						|
- name: Build clean mapper payload
 | 
						|
  set_fact:
 | 
						|
    desired_group_mapper: >-
 | 
						|
      {{
 | 
						|
        desired_group_mapper_raw
 | 
						|
        | dict2items
 | 
						|
        | rejectattr('key','in',['subComponents','id'])
 | 
						|
        | list | items2dict
 | 
						|
      }}
 | 
						|
 | 
						|
- name: Extract desired groups.path (if any)
 | 
						|
  set_fact:
 | 
						|
    desired_groups_path: "{{ (desired_group_mapper.config['groups.path'] | default([])) | first | default('') | trim }}"
 | 
						|
    desired_groups_top: "{{ ( (desired_group_mapper.config['groups.path'] | default([])) | first | default('') | trim ).lstrip('/') | split('/') | first | default('') }}"
 | 
						|
  changed_when: false
 | 
						|
 | 
						|
- name: Resolve existing top-level group id for groups.path
 | 
						|
  when: desired_groups_top | length > 0
 | 
						|
  shell: >
 | 
						|
    {{ KEYCLOAK_EXEC_KCADM }} get groups -r {{ KEYCLOAK_REALM }} --format json
 | 
						|
    | jq -r '.[] | select(.name=="{{ desired_groups_top }}") | .id' | head -n1
 | 
						|
  register: groups_top_id
 | 
						|
  changed_when: false
 | 
						|
 | 
						|
- name: Create top-level group for groups.path if missing
 | 
						|
  when:
 | 
						|
    - desired_groups_top | length > 0
 | 
						|
    - (groups_top_id.stdout | trim) in ["", "null"]
 | 
						|
  shell: >
 | 
						|
    {{ KEYCLOAK_EXEC_KCADM }} create groups -r {{ KEYCLOAK_REALM }} -s name={{ desired_groups_top }}
 | 
						|
  register: create_groups_top
 | 
						|
  changed_when: create_groups_top.rc == 0
 | 
						|
  failed_when: create_groups_top.rc != 0 and ('already exists' not in (create_groups_top.stderr | lower))
 | 
						|
 | 
						|
- name: Find existing 'ldap-roles' mapper under LDAP component
 | 
						|
  shell: >
 | 
						|
    {{ KEYCLOAK_EXEC_KCADM }} get components
 | 
						|
    -r {{ KEYCLOAK_REALM }}
 | 
						|
    --query "parent={{ ldap_cmp_id.stdout | trim }}&type=org.keycloak.storage.ldap.mappers.LDAPStorageMapper&name=ldap-roles"
 | 
						|
    --format json
 | 
						|
    | jq -r '.[] | select(.parentId=="{{ ldap_cmp_id.stdout | trim }}" and .name=="ldap-roles") | .id' | head -n1
 | 
						|
  register: grp_mapper_id
 | 
						|
  changed_when: false
 | 
						|
 | 
						|
- name: Create 'ldap-roles' mapper if missing
 | 
						|
  when: (grp_mapper_id.stdout | trim) in ["", "null"]
 | 
						|
  shell: |
 | 
						|
    cat <<'JSON' | {{ KEYCLOAK_EXEC_KCADM }} create components -r {{ KEYCLOAK_REALM }} -f -
 | 
						|
    {{
 | 
						|
      desired_group_mapper
 | 
						|
      | combine({
 | 
						|
          'name':         'ldap-roles',
 | 
						|
          'parentId':     ldap_cmp_id.stdout | trim,
 | 
						|
          'providerType': 'org.keycloak.storage.ldap.mappers.LDAPStorageMapper',
 | 
						|
          'providerId':   'group-ldap-mapper'
 | 
						|
        }, recursive=True)
 | 
						|
      | to_json
 | 
						|
    }}
 | 
						|
    JSON
 | 
						|
  register: create_mapper
 | 
						|
  changed_when: create_mapper.rc == 0
 | 
						|
  failed_when: create_mapper.rc != 0 and ('already exists' not in (create_mapper.stderr | lower))
 | 
						|
  no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
 | 
						|
 | 
						|
- name: Update 'ldap-roles' mapper config (merge only .config)
 | 
						|
  when: (grp_mapper_id.stdout | trim) not in ["", "null"]
 | 
						|
  vars:
 | 
						|
    kc_object_kind:  "component"
 | 
						|
    kc_lookup_field: "id"
 | 
						|
    kc_lookup_value: "{{ grp_mapper_id.stdout | trim }}"
 | 
						|
    kc_desired: >-
 | 
						|
      {{
 | 
						|
        desired_group_mapper
 | 
						|
        | combine({
 | 
						|
            'name':         'ldap-roles',
 | 
						|
            'parentId':     ldap_cmp_id.stdout | trim,
 | 
						|
            'providerType': 'org.keycloak.storage.ldap.mappers.LDAPStorageMapper',
 | 
						|
            'providerId':   'group-ldap-mapper'
 | 
						|
          }, recursive=True)
 | 
						|
      }}
 | 
						|
    kc_merge_path:   "config"
 | 
						|
  include_tasks: _update.yml
 |