heat_template_version: rocky

description: >
  Configures docker on the host

parameters:
  DockerInsecureRegistryAddress:
    description: Optional. The IP Address and Port of an insecure docker
                 namespace that will be configured in /etc/sysconfig/docker.
                 The value can be multiple addresses separated by commas.
    type: comma_delimited_list
    default: []
  DockerRegistryMirror:
    description: Optional. Mirror to use for registry docker.io
    default: ''
    type: string
  EndpointMap:
    default: {}
    description: Mapping of service endpoint -> protocol. Typically set
                 via parameter_defaults in the resource registry.
    type: json
  ServiceData:
    default: {}
    description: Dictionary packing service data
    type: json
  ServiceNetMap:
    default: {}
    description: Mapping of service_name -> network name. Typically set
                 via parameter_defaults in the resource registry.  This
                 mapping overrides those in ServiceNetMapDefaults.
    type: json
  DefaultPasswords:
    default: {}
    type: json
  RoleName:
    default: ''
    description: Role name on which the service is applied
    type: string
  RoleParameters:
    default: {}
    description: Parameters specific to the role
    type: json
  Debug:
    type: boolean
    default: false
    description: Set to True to enable debugging on all services.
  DockerDebug:
    default: ''
    description: Set to True to enable debugging Docker services.
    type: string
    constraints:
      - allowed_values: [ '', 'true', 'True', 'TRUE', 'false', 'False', 'FALSE']
  DockerOptions:
    default: '--log-driver=journald --signature-verification=false --iptables=false --live-restore'
    description: Options that are used to startup the docker service.
    type: string
  DockerAdditionalSockets:
    default: ['/var/lib/openstack/docker.sock']
    description: Additional domain sockets for the docker daemon to bind to (useful for mounting
                 into containers that launch other containers)
    type: comma_delimited_list
  DockerNetworkOptions:
    default: '--bip=172.31.0.1/24'
    description: More startup options, like CIDR for the default docker0 bridge (useful for the
                 network configuration conflicts resolution)
    type: string
  DeploymentUser:
    default: ''
    description: User added to the docker group in order to use container commands.
    type: string
  DockerSkipUpdateReconfiguration:
    default: false
    type: boolean
    description: Flag to disable docker reconfiguration during stack update.
    tags:
      - role_specific
  ContainerImageRegistryLogin:
    type: boolean
    default: false
    description: Flag to enable container registry login actions during the deployment.
                 Setting this to true will cause login calls to be performed during the
                 deployment.
  ContainerImageRegistryCredentials:
    type: json
    hidden: true
    default: {}
    description: |
      Mapping of image registry hosts to login credentials. Must be in the following example format

        docker.io:
          username: pa55word
        '192.0.2.1:8787':
          registry_username: password
  SELinuxMode:
    default: 'enforcing'
    description: Configures SELinux mode
    type: string
    constraints:
      - allowed_values: [ 'enforcing', 'permissive', 'disabled' ]
parameter_groups:
- label: deprecated
  description: |
   The following parameters are deprecated and will be removed. They should not
   be relied on for new deployments. If you have concerns regarding deprecated
   parameters, please contact the TripleO development team on IRC or the
   OpenStack mailing list.
  parameters:
  - DockerAdditionalSockets

resources:
  # Merging role-specific parameters (RoleParameters) with the default parameters.
  # RoleParameters will have the precedence over the default parameters.
  RoleParametersValue:
    type: OS::Heat::Value
    properties:
      type: json
      value:
        map_replace:
          - map_replace:
            - DockerSkipUpdateReconfiguration: DockerSkipUpdateReconfiguration
            - values: {get_param: [RoleParameters]}
          - values:
              DockerSkipUpdateReconfiguration: {get_param: DockerSkipUpdateReconfiguration}

conditions:
  insecure_registry_is_empty: {equals : [{get_param: DockerInsecureRegistryAddress}, []]}
  service_debug_unset: {equals : [{get_param: DockerDebug}, '']}
  selinux_enforcing: {equals : [{get_param: SELinuxMode}, 'enforcing']}

outputs:
  role_data:
    description: Role data for the docker service
    value:
      service_name: docker
      config_settings: {}
      step_config: ''
      host_prep_tasks:
        - name: Install, Configure and Run Docker
          block:
          # NOTE(bogdando): w/a https://github.com/ansible/ansible/issues/42621
          - set_fact: &docker_vars
              container_registry_debug:
                if:
                  - service_debug_unset
                  - {get_param: Debug }
                  - {get_param: DockerDebug}
              container_registry_deployment_user: {get_param: DeploymentUser}
              container_registry_docker_options: {get_param: DockerOptions}
              container_registry_additional_sockets: {get_param: DockerAdditionalSockets}
              container_registry_insecure_registries:
                if:
                  - insecure_registry_is_empty
                  - []
                  - {get_param: DockerInsecureRegistryAddress}
              container_registry_mirror: {get_param: DockerRegistryMirror}
              container_registry_network_options: {get_param: DockerNetworkOptions}
              container_registry_skip_reconfiguration: {get_attr: [RoleParametersValue, value, DockerSkipUpdateReconfiguration]}
              container_registry_selinux:
                if:
                  - selinux_enforcing
                  - true
                  - false
              container_registry_login: {get_param: ContainerImageRegistryLogin}
              # default that is overwritten by the heat -> dict conversion
              container_registry_logins: {}
              container_registry_logins_json: {get_param: ContainerImageRegistryCredentials}
          - name: Convert logins json to dict
            set_fact:
              container_registry_logins: "{{ container_registry_logins_json | from_json }}"
            when:
              - container_registry_logins_json is string
              - container_registry_login | bool
              - (container_registry_logins_json | length) > 0
          - name: Set registry logins
            set_fact:
              container_registry_logins: "{{ container_registry_logins_json }}"
            when:
              - container_registry_logins_json is mapping
              - container_registry_login | bool
              - (container_registry_logins_json | length) > 0
          - include_role:
              name: container-registry
              tasks_from: docker
          - include_role:
              name: container-registry
              tasks_from: docker-login
            when: container_registry_login|bool
      service_config_settings:
        neutron_l3:
          docker_additional_sockets: {get_param: DockerAdditionalSockets}
        neutron_dhcp:
          docker_additional_sockets: {get_param: DockerAdditionalSockets}
        ovn_metadata:
          docker_additional_sockets: {get_param: DockerAdditionalSockets}
      upgrade_tasks:
        - block:
            - name: Install docker packages on upgrade if missing
              package: name=docker state=latest
            - set_fact: *docker_vars
            - name: Reconfigure Docker if needed
              include_role:
                name: container-registry
                tasks_from: docker
          when: step|int == 3
      post_upgrade_tasks:
        - name: Clean docker
          when:
            - step|int == 3
            - container_cli == 'docker'
          block:
            - name: Check if docker has some data
              stat:
                path: /var/lib/docker
              register: docker_path_stat
            - name: Purge Docker
              when: docker_path_stat.stat.exists
              block:
                - name: Ensure docker service is running
                  systemd:
                    name: docker
                  register: docker_service_state
                - name: Run docker system prune
                  shell: docker system prune -a -f
                  when: docker_service_state.status['SubState'] == 'running'
      update_tasks:
        - name: Restart Docker when needed
          when: step|int == 2
          block:
          - set_fact: *docker_vars
          - include_role:
              name: container-registry
              tasks_from: docker-update
      post_update_tasks:
        - name: Clean docker
          when:
            - step|int == 3
            - container_cli == 'docker'
          block:
            - name: Check if docker has some data
              stat:
                path: /var/lib/docker
              register: docker_path_stat
            - name: Purge Docker
              when: docker_path_stat.stat.exists
              block:
                - name: Ensure docker service is running
                  systemd:
                    name: docker
                  register: docker_service_state
                - name: Run docker image prune
                  shell: docker image prune -f
                  when: docker_service_state.status['SubState'] == 'running'
                - name: Run docker volume prune
                  shell: docker volume prune -f
                  when: docker_service_state.status['SubState'] == 'running'
