heat_template_version: rocky

description: >
  OpenStack containerized gnocchi service

parameters:
  ContainerGnocchiApiImage:
    description: image
    type: string
  ContainerGnocchiConfigImage:
    description: The container image to use for the gnocchi config_volume
    type: string
  GnocchiApiLoggingSource:
    type: json
    default:
      tag: openstack.gnocchi.api
      file: /var/log/containers/gnocchi/app.log
  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
  EnableInternalTLS:
    type: boolean
    default: false
  NumberOfStorageSacks:
    default: 128
    description: Number of storage sacks to create.
    type: number
  CephClientUserName:
    default: openstack
    type: string
  CephClusterName:
    type: string
    default: ceph
    description: The Ceph cluster name.
    constraints:
    - allowed_pattern: "[a-zA-Z0-9]+"
      description: >
        The Ceph cluster name must be at least 1 character and contain only
        letters and numbers.
  GnocchiFileBasePath:
    default: '/var/lib/gnocchi'
    description: Path to use when file driver is used. This could be NFS or a
      flat file.
    type: string
  GnocchiPassword:
    description: The password for the gnocchi service and db account.
    type: string
    hidden: true
  GnocchiBackend:
    default: swift
    description: The short name of the Gnocchi backend to use. Should be one
      of swift, rbd, file or s3.
    type: string
    constraints:
    - allowed_values: ['swift', 'file', 'rbd', 's3']
  GnocchiIncomingStorageDriver:
    default: redis
    description: Storage driver to use for incoming metric data
    type: string
  KeystoneRegion:
    type: string
    default: 'regionOne'
    description: Keystone region for endpoint
  MonitoringSubscriptionGnocchiApi:
    default: 'overcloud-gnocchi-api'
    type: string
  GnocchiApiLoggingSource:
    type: json
    default:
      tag: openstack.gnocchi.api
      path: /var/log/gnocchi/app.log
  EnableInternalTLS:
    type: boolean
    default: false
  GnocchiApiPolicies:
    description: |
      A hash of policies to configure for Gnocchi API.
      e.g. { gnocchi-context_is_admin: { key: context_is_admin, value: 'role:admin' } }
    default: {}
    type: json
  GnocchiCorsAllowedOrigin:
    type: string
    default: ''
    description: Indicate whether this resource may be shared with the domain received in the request
                 "origin" header.

conditions:
  cors_allowed_origin_unset: {equals : [{get_param: GnocchiCorsAllowedOrigin}, '']}
  internal_tls_enabled: {equals: [{get_param: EnableInternalTLS}, true]}

resources:

  ContainersCommon:
    type: ../containers-common.yaml

  GnocchiServiceBase:
    type: ./gnocchi-base.yaml
    properties:
      ServiceData: {get_param: ServiceData}
      ServiceNetMap: {get_param: ServiceNetMap}
      DefaultPasswords: {get_param: DefaultPasswords}
      EndpointMap: {get_param: EndpointMap}
      RoleName: {get_param: RoleName}
      RoleParameters: {get_param: RoleParameters}

  ApacheServiceBase:
    type: ../../deployment/apache/apache-baremetal-puppet.yaml
    properties:
      ServiceData: {get_param: ServiceData}
      ServiceNetMap: {get_param: ServiceNetMap}
      DefaultPasswords: {get_param: DefaultPasswords}
      EndpointMap: {get_param: EndpointMap}
      RoleName: {get_param: RoleName}
      RoleParameters: {get_param: RoleParameters}
      EnableInternalTLS: {get_param: EnableInternalTLS}

outputs:
  role_data:
    description: Role data for the gnocchi API role.
    value:
      service_name: gnocchi_api
      firewall_rules:
        '129 gnocchi-api':
          dport:
            - 8041
            - 13041
      monitoring_subscription: {get_param: MonitoringSubscriptionGnocchiApi}
      config_settings:
        map_merge:
          - get_attr: [GnocchiServiceBase, role_data, config_settings]
          - get_attr: [ApacheServiceBase, role_data, config_settings]
          - apache::default_vhost: false
          -
            if:
            - cors_allowed_origin_unset
            - {}
            - gnocchi::cors::allowed_origin: {get_param: GnocchiCorsAllowedOrigin}
              gnocchi::api::middlewares: 'oslo_middleware.cors.CORS'
          - gnocchi::api::enabled: true
            gnocchi::api::enable_proxy_headers_parsing: true
            gnocchi::api::service_name: 'httpd'
            gnocchi::policy::policies: {get_param: GnocchiApiPolicies}
            gnocchi::cors::max_age: 3600
            gnocchi::cors::allow_headers: 'Content-Type,Cache-Control,Content-Language,Expires,Last-Modified,Pragma,X-Auth-Token'
            gnocchi::cors::expose_headers: 'Content-Type,Cache-Control,Content-Language,Expires,Last-Modified,Pragma'
            gnocchi::cors::allow_methods: 'GET,POST,PUT,DELETE,OPTIONS,PATCH'
            gnocchi::keystone::authtoken::www_authenticate_uri: {get_param: [EndpointMap, KeystoneInternal, uri_no_suffix]}
            gnocchi::keystone::authtoken::auth_uri: {get_param: [EndpointMap, KeystoneInternal, uri_no_suffix]}
            gnocchi::keystone::authtoken::auth_url: {get_param: [EndpointMap, KeystoneInternal, uri_no_suffix]}
            gnocchi::keystone::authtoken::password: {get_param: GnocchiPassword}
            gnocchi::keystone::authtoken::project_name: 'service'
            gnocchi::keystone::authtoken::user_domain_name: 'Default'
            gnocchi::keystone::authtoken::project_domain_name: 'Default'
            gnocchi::wsgi::apache::ssl: {get_param: EnableInternalTLS}
            gnocchi::wsgi::apache::servername:
              str_replace:
                template:
                  "%{hiera('fqdn_$NETWORK')}"
                params:
                  $NETWORK: {get_param: [ServiceNetMap, GnocchiApiNetwork]}
            tripleo::profile::base::gnocchi::api::gnocchi_backend: {get_param: GnocchiBackend}
            tripleo::profile::base::gnocchi::api::incoming_storage_driver: {get_param: GnocchiIncomingStorageDriver}
            # NOTE: bind IP is found in hiera replacing the network name with the
            # local node IP for the given network; replacement examples
            # (eg. for internal_api):
            # internal_api -> IP
            # internal_api_uri -> [IP]
            # internal_api_subnet - > IP/CIDR
            gnocchi::wsgi::apache::bind_host:
              str_replace:
                template:
                  "%{hiera('$NETWORK')}"
                params:
                  $NETWORK: {get_param: [ServiceNetMap, GnocchiApiNetwork]}
            gnocchi::wsgi::apache::wsgi_process_display_name: 'gnocchi_wsgi'
      service_config_settings:
        map_merge:
          - get_attr: [GnocchiServiceBase, role_data, service_config_settings]
          - rsyslog:
              tripleo_logging_sources_gnocchi_api:
                - {get_param: GnocchiApiLoggingSource}
            keystone:
              gnocchi::keystone::auth::admin_url: { get_param: [ EndpointMap, GnocchiAdmin, uri ] }
              gnocchi::keystone::auth::internal_url: {get_param: [EndpointMap, GnocchiInternal, uri]}
              gnocchi::keystone::auth::password: {get_param: GnocchiPassword}
              gnocchi::keystone::auth::public_url: { get_param: [ EndpointMap, GnocchiPublic, uri ] }
              gnocchi::keystone::auth::region: {get_param: KeystoneRegion}
              gnocchi::keystone::auth::tenant: 'service'
            mysql:
              gnocchi::db::mysql::password: {get_param: GnocchiPassword}
              gnocchi::db::mysql::user: gnocchi
              gnocchi::db::mysql::host: {get_param: [EndpointMap, MysqlInternal, host_nobrackets]}
              gnocchi::db::mysql::dbname: gnocchi
              gnocchi::db::mysql::allowed_hosts:
                - '%'
                - "%{hiera('mysql_bind_host')}"
      # BEGIN DOCKER SETTINGS
      puppet_config:
        config_volume: gnocchi
        puppet_tags: gnocchi_api_paste_ini,gnocchi_config
        step_config: |
          include ::tripleo::profile::base::gnocchi::api
        config_image: {get_param: ContainerGnocchiConfigImage}
      kolla_config:
        /var/lib/kolla/config_files/gnocchi_api.json:
          command: /usr/sbin/httpd -DFOREGROUND
          config_files: &gnocchi_api_kolla_config_files
            - source: "/var/lib/kolla/config_files/src/etc/httpd/conf.d"
              dest: "/etc/httpd/conf.d"
              merge: false
              preserve_properties: true
            - source: "/var/lib/kolla/config_files/src/*"
              dest: "/"
              merge: true
              preserve_properties: true
            - source: "/var/lib/kolla/config_files/src-ceph/"
              dest: "/etc/ceph/"
              merge: true
              preserve_properties: true
          permissions: &gnocchi_api_kolla_permissions
            - path: /var/log/gnocchi
              owner: gnocchi:gnocchi
              recurse: true
            - path:
                str_replace:
                  template: /etc/ceph/CLUSTER.client.USER.keyring
                  params:
                    CLUSTER: {get_param: CephClusterName}
                    USER: {get_param: CephClientUserName}
              owner: gnocchi:gnocchi
              perm: '0600'
            - path:
                list_join:
                  - "/"
                  - - {get_param: GnocchiFileBasePath}
                    - "tmp"
              owner: gnocchi:gnocchi
              perm: '0750'
              recurse: true
        /var/lib/kolla/config_files/gnocchi_db_sync.json:
          command:
            str_replace:
              template: /usr/bin/bootstrap_host_exec gnocchi_api /usr/bin/gnocchi-upgrade --sacks-number=SACK_NUM
              params:
                SACK_NUM: {get_param: NumberOfStorageSacks}
          config_files: *gnocchi_api_kolla_config_files
          permissions: *gnocchi_api_kolla_permissions
      docker_config:
        # db sync runs before permissions set by kolla_config
        step_2:
          gnocchi_init_log:
            image: &gnocchi_api_image {get_param: ContainerGnocchiApiImage}
            net: none
            user: root
            volumes:
              - /var/log/containers/gnocchi:/var/log/gnocchi:z
              - /var/log/containers/httpd/gnocchi-api:/var/log/httpd:z
            command: ['/bin/bash', '-c', 'chown -R gnocchi:gnocchi /var/log/gnocchi']
          gnocchi_init_lib:
            image: *gnocchi_api_image
            net: none
            user: root
            volumes:
              - str_replace:
                  template: GNOCCHI_FILE_BASE_PATH:GNOCCHI_FILE_BASE_PATH:SE_FLAGS
                  params: {GNOCCHI_FILE_BASE_PATH: {get_param: GnocchiFileBasePath}, SE_FLAGS: 'shared,z'}
            command:
              - '/bin/bash'
              - '-c'
              - str_replace:
                  template: 'chown -R gnocchi:gnocchi GNOCCHI_FILE_BASE_PATH'
                  params: {GNOCCHI_FILE_BASE_PATH: {get_param: GnocchiFileBasePath}}
        step_5:
          gnocchi_db_sync:
            start_order: 0
            image: *gnocchi_api_image
            net: host
            detach: false
            privileged: false
            user: root
            volumes:
              list_concat:
                - {get_attr: [ContainersCommon, volumes]}
                -
                  - /var/lib/kolla/config_files/gnocchi_db_sync.json:/var/lib/kolla/config_files/config.json:ro
                  - /var/lib/config-data/puppet-generated/gnocchi/:/var/lib/kolla/config_files/src:ro
                  - str_replace:
                      template: GNOCCHI_FILE_BASE_PATH:GNOCCHI_FILE_BASE_PATH:SE_FLAGS
                      params: {GNOCCHI_FILE_BASE_PATH: {get_param: GnocchiFileBasePath}, SE_FLAGS: 'shared,z'}
                  - /var/log/containers/gnocchi:/var/log/gnocchi:z
                  - /var/log/containers/httpd/gnocchi-api:/var/log/httpd:z
                  - /etc/ceph:/var/lib/kolla/config_files/src-ceph:ro
            environment:
              KOLLA_CONFIG_STRATEGY: COPY_ALWAYS
          gnocchi_api:
            image: *gnocchi_api_image
            start_order: 1
            net: host
            privileged: false
            restart: always
            healthcheck:
              test: /openstack/healthcheck
            volumes:
              list_concat:
                - {get_attr: [ContainersCommon, volumes]}
                -
                  - str_replace:
                      template: GNOCCHI_FILE_BASE_PATH:GNOCCHI_FILE_BASE_PATH:SE_FLAGS
                      params: {GNOCCHI_FILE_BASE_PATH: {get_param: GnocchiFileBasePath}, SE_FLAGS: 'shared,z'}
                  - /var/lib/kolla/config_files/gnocchi_api.json:/var/lib/kolla/config_files/config.json:ro
                  - /var/lib/config-data/puppet-generated/gnocchi/:/var/lib/kolla/config_files/src:ro
                  - /var/log/containers/gnocchi:/var/log/gnocchi:z
                  - /var/log/containers/httpd/gnocchi-api:/var/log/httpd:z
                  - /etc/ceph:/var/lib/kolla/config_files/src-ceph:ro
                  -
                    if:
                      - internal_tls_enabled
                      - /etc/pki/tls/certs/httpd:/etc/pki/tls/certs/httpd:ro
                      - ''
                  -
                    if:
                      - internal_tls_enabled
                      - /etc/pki/tls/private/httpd:/etc/pki/tls/private/httpd:ro
                      - ''
            environment:
              KOLLA_CONFIG_STRATEGY: COPY_ALWAYS
      host_prep_tasks:
        - name: create persistent data and logs directory
          file:
            path: "{{ item.path }}"
            state: directory
            setype: "{{ item.setype }}"
          with_items:
            - { 'path': /var/log/containers/gnocchi, 'setype': svirt_sandbox_file_t, 'mode': '0750' }
            - { 'path': /var/log/containers/httpd/gnocchi-api, 'setype': svirt_sandbox_file_t, 'mode': '0750' }
            - { 'path': {get_param: GnocchiFileBasePath}, 'setype': svirt_sandbox_file_t }
        - name: ensure ceph configurations exist
          file:
            path: /etc/ceph
            state: directory
      upgrade_tasks: []
      metadata_settings:
        get_attr: [ApacheServiceBase, role_data, metadata_settings]
      external_upgrade_tasks:
        - when:
            - step|int == 1
          tags:
            - never
            - system_upgrade_transfer_data
            - system_upgrade_stop_services
          block:
            - name: Stop gnocchi container
              import_role:
                name: tripleo-container-stop
              vars:
                tripleo_containers_to_stop:
                  - gnocchi_api
                tripleo_delegate_to: "{{ groups['gnocchi_api'] | default([]) }}"
      fast_forward_upgrade_tasks:
        - when:
            - step|int == 0
            - release == 'ocata'
          block:
            - name: Check if httpd service is running
              command: systemctl is-active --quiet httpd
              tags: common
              ignore_errors: True
              register: httpd_running_result
              when:
                - httpd_running is undefined
            - name: Set fact httpd_running if unset
              set_fact:
                httpd_running: "{{ httpd_running_result.rc == 0 }}"
              when:
                - httpd_running is undefined
            - name: Check if gnocchi_api is deployed
              command: systemctl is-enabled --quiet openstack-gnocchi-api
              tags: common
              ignore_errors: True
              register: gnocchi_api_enabled_result
            - name: Set fact gnocchi_api_enabled
              set_fact:
                gnocchi_api_enabled: "{{ gnocchi_api_enabled_result.rc == 0 }}"
            - name: Check for gnocchi_api running under apache
              tags: common
              shell: "httpd -t -D DUMP_VHOSTS | grep -q gnocchi"
              ignore_errors: True
              register: gnocchi_httpd_enabled_result
            - name: Set fact gnocchi_httpd_enabled
              set_fact:
                gnocchi_httpd_enabled: "{{ gnocchi_httpd_enabled_result.rc == 0 }}"
        - name: Stop and disable gnocchi_api service
          service: name=openstack-gnocchi-api state=stopped enabled=no
          when:
            - step|int == 1
            - release == 'ocata'
            - gnocchi_api_enabled|bool
        - name: Stop and disable httpd service
          when:
            - step|int == 1
            - release == 'ocata'
            - gnocchi_httpd_enabled|bool
            - httpd_running|bool
          service: name=httpd state=stopped enabled=no
        - name: Update gnocchi packages
          package:
            name:
              - openstack-gnocchi*
              - numpy
            state: latest
          # (pradk): We have to explicitly update numpy as its obsoleted
          # by python2-numpy.
          when:
            - step|int == 6
            - is_bootstrap_node|bool
        - name: Sync gnocchi DB
          command: gnocchi-upgrade --skip-storage
          when:
            - step|int == 8
            - is_bootstrap_node|bool
            - gnocchi_api_enabled|bool
