---
version: '2.0'
name: tripleo.plan_management.v1
description: TripleO Overcloud Deployment Workflows v1

workflows:

  create_container:
    description: >
      Creates an object container for a given name.  If a container with the
      same name already exists an error is returned.

    tags:
      - tripleo-common-managed

    input:
      - container: overcloud
      - queue_name: tripleo

    tasks:
      create_container:
        action: tripleo.plan.create_container container=<% $.container %>
        on-complete: send_message
        publish-on-error:
          status: FAILED
          message: <% task().result %>
        publish:
          status: SUCCESS
          message: <% task().result %>

      send_message:
        workflow: tripleo.messaging.v1.send
        input:
          queue_name: <% $.queue_name %>
          type: <% execution().name %>
          status: <% $.status %>
          message: <% $.get('message', '') %>
          execution: <% execution() %>
          plan_name: <% $.container %>

  create_deployment_plan:
    description: >
      This workflow provides the capability to create a deployment plan using
      the default heat templates provided in a standard TripleO undercloud
      deployment, heat templates contained in an external git repository, or a
      swift container that already contains templates.
    input:
      - container
      - source_url: null
      - queue_name: tripleo
      - generate_passwords: true
      - use_default_templates: false
      - validate_stack: true

    tags:
      - tripleo-common-managed

    tasks:
      container_required_check:
        description: >
          If using the default templates or importing templates from a git
          repository, a new container needs to be created.  If using an existing
          container containing templates, skip straight to create_plan.
        on-success:
          - verify_container_doesnt_exist: <% $.use_default_templates or $.source_url %>
          - create_plan: <% $.use_default_templates = false and $.source_url = null %>

      verify_container_doesnt_exist:
        workflow: tripleo.swift.v1.container_exists
        input:
          container: <% $.container %>
        publish:
          status: FAILED
          message: "Unable to create plan. The Swift container already exists"
        on-success: send_message
        on-error: create_container

      create_container:
        action: tripleo.plan.create_container container=<% $.container %>
        on-success: templates_source_check
        publish-on-error:
          status: FAILED
          message: <% task().result %>
        on-error: send_message

      cleanup_temporary_files:
        action: tripleo.git.clean container=<% $.container %>

      templates_source_check:
        on-success:
          - upload_default_templates: <% $.use_default_templates = true %>
          - clone_git_repo: <% $.source_url != null %>

      clone_git_repo:
        action: tripleo.git.clone container=<% $.container %> url=<% $.source_url %>
        on-success: upload_templates_directory
        on-error: clone_git_repo_set_status_failed

      upload_templates_directory:
        action: tripleo.templates.upload container=<% $.container %> dir_to_upload=<% task(clone_git_repo).result %>
        on-success: create_plan
        on-complete: cleanup_temporary_files
        on-error: upload_templates_directory_set_status_failed

      upload_default_templates:
        action: tripleo.templates.upload container=<% $.container %>
        on-success: create_plan
        on-error: upload_to_container_set_status_failed

      create_plan:
        on-success:
          - ensure_plan_environment_exists

      # This selects the default "openstack" sample plan if no user
      # provided plan-environment.yaml or capabilities-map.yaml exists
      # Note in the case where a user provided plan-environment.yaml
      # exists we'll still copy the missing capabilities-map.yaml
      ensure_plan_environment_exists:
        workflow: tripleo.plan_management.v1._check_plan_environment
        input:
          container: <% $.container %>
          queue_name: <% queue_name %>
        on-success:
          - ensure_passwords_exist: <% $.generate_passwords = true %>
          - add_root_stack_name: <% $.generate_passwords != true %>

      ensure_passwords_exist:
        action: tripleo.parameters.generate_passwords container=<% $.container %>
        on-success: add_root_stack_name
        on-error: ensure_passwords_exist_set_status_failed

      add_root_stack_name:
        action: tripleo.parameters.update
        input:
          container: <% $.container %>
          validate: <% $.validate_stack %>
          parameters:
            RootStackName: <% $.container %>
        on-success: container_images_prepare
        publish-on-error:
          status: FAILED
          message: <% task().result %>
        on-error: send_message

      container_images_prepare:
        description: >
          Populate all container image parameters with default values.
        action: tripleo.container_images.prepare container=<% $.container %>
        on-success: process_templates
        on-error: container_images_prepare_set_status_failed

      process_templates:
        action: tripleo.templates.process container=<% $.container %>
        on-success: set_status_success
        on-error: process_templates_set_status_failed

      set_status_success:
        on-success: send_message
        publish:
          status: SUCCESS
          message: 'Plan created.'

      clone_git_repo_set_status_failed:
        on-success: send_message
        publish:
          status: FAILED
          message: <% task(clone_git_repo).result %>

      upload_templates_directory_set_status_failed:
        on-success: send_message
        publish:
          status: FAILED
          message: <% task(upload_templates_directory).result %>

      upload_to_container_set_status_failed:
        on-success: send_message
        publish:
          status: FAILED
          message: <% task(upload_default_templates).result %>

      ensure_passwords_exist_set_status_failed:
        on-success: send_message
        publish:
          status: FAILED
          message: <% task(ensure_passwords_exist).result %>

      process_templates_set_status_failed:
        on-success: send_message
        publish:
          status: FAILED
          message: <% task(process_templates).result %>

      container_images_prepare_set_status_failed:
        on-success: send_message
        publish:
          status: FAILED
          message: <% task(container_images_prepare).result %>

      send_message:
        workflow: tripleo.messaging.v1.send
        input:
          queue_name: <% $.queue_name %>
          type: <% execution().name %>
          status: <% $.status %>
          execution: <% execution() %>
          plan_name: <% $.container %>
          message: <% $.get('message', '') %>
          deployment_status: UNDEPLOYED

  _check_plan_environment:
    input:
      - container
      - queue_name
    tags:
      - tripleo-common-managed
    tasks:
      check_for_plan_env:
        workflow: tripleo.swift.v1.object_exists
        input:
          container: <% $.container %>
          object: plan-environment.yaml
        on-error: select_default_sample_plan
        on-success: check_for_capabilities_map

      check_for_capabilities_map:
        workflow: tripleo.swift.v1.object_exists
        input:
          container: <% $.container %>
          object: capabilities-map.yaml
        on-error: select_default_sample_plan

      # If there's no existing or user-defined plan-environment.yaml
      # We run select_default_sample_plan with the default sample_plan_name
      # to select the openstack default openstack plan
      # Note in the case where plan-environment.yaml exists we'll skip
      # copying that and only copy the capabilities-map.yaml, which is
      # needed when a user provides a plan-environment.yaml - to select
      # a new sample plan it will be necessary to delete both files
      # from the root of the plan.
      select_default_sample_plan:
        workflow: tripleo.plan_management.v1.select_sample_plan
        input:
          container: <% $.container %>
          queue_name: <% queue_name %>

  update_deployment_plan:
    input:
      - container
      - source_url: null
      - queue_name: tripleo
      - generate_passwords: true
      - plan_environment: null
      - validate_stack: true
    tags:
      - tripleo-common-managed
    tasks:
      templates_source_check:
        on-success:
          - update_plan: <% $.source_url = null %>
          - clone_git_repo: <% $.source_url != null %>

      clone_git_repo:
        action: tripleo.git.clone container=<% $.container %> url=<% $.source_url %>
        on-success: upload_templates_directory
        on-error: clone_git_repo_set_status_failed

      upload_templates_directory:
        action: tripleo.templates.upload container=<% $.container %> dir_to_upload=<% task(clone_git_repo).result %>
        on-success: update_plan
        on-complete: cleanup_temporary_files
        on-error: upload_templates_directory_set_status_failed

      cleanup_temporary_files:
        action: tripleo.git.clean container=<% $.container %>

      update_plan:
        on-success:
          - ensure_passwords_exist: <% $.generate_passwords = true %>
          - container_images_prepare: <% $.generate_passwords != true %>

      ensure_passwords_exist:
        action: tripleo.parameters.generate_passwords container=<% $.container %>
        on-success: container_images_prepare
        on-error: ensure_passwords_exist_set_status_failed

      container_images_prepare:
        description: >
          Populate all container image parameters with default values.
        action: tripleo.container_images.prepare container=<% $.container %>
        on-success: create_swift_rings_backup_plan
        on-error: container_images_prepare_set_status_failed

      create_swift_rings_backup_plan:
        workflow: tripleo.swift_backup.v1.create_swift_backup_container_plan
        on-success: create_ceph_ansible_fetch_directory_backup_plan
        on-error: create_swift_rings_backup_plan_set_status_failed
        input:
          container: <% $.container %>
          queue_name: <% $.queue_name %>
          container_suffix: "-swift-rings"
          swift_tar: "swift-rings.tar.gz"
          get_url_parm: SwiftRingGetTempurl
          put_url_parm: SwiftRingPutTempurl
          use_default_templates: true
          validate_stack: <% $.validate_stack %>

      create_ceph_ansible_fetch_directory_backup_plan:
        workflow: tripleo.swift_backup.v1.create_swift_backup_container_plan
        on-success: does_ceph_ansible_fetch_directory_backup_need_rename
        on-error: create_ceph_ansible_fetch_directory_backup_plan_set_status_failed
        input:
          container: <% $.container %>
          queue_name: <% $.queue_name %>
          container_suffix: "_ceph_ansible_fetch_dir"
          swift_tar: "temporary_dir.tar.gz"
          get_url_parm: SwiftFetchDirGetTempurl
          put_url_parm: SwiftFetchDirPutTempurl
          use_default_templates: true
          validate_stack: <% $.validate_stack %>

      does_ceph_ansible_fetch_directory_backup_need_rename:
        workflow: tripleo.rename_ceph_ansible_fetch_directory.v1.check_and_rename
        on-success: process_templates
        on-error: does_ceph_ansible_fetch_directory_backup_need_rename_set_status_failed
        input:
          container: <% $.container %>
          queue_name: <% $.queue_name %>
          container_suffix: "_ceph_ansible_fetch_dir"
          swift_tar: "temporary_dir.tar.gz"

      process_templates:
        action: tripleo.templates.process container=<% $.container %>
        on-success:
          - set_status_success: <% $.plan_environment = null %>
          - upload_plan_environment: <% $.plan_environment != null %>
        on-error: process_templates_set_status_failed

      upload_plan_environment:
        action: tripleo.templates.upload_plan_environment container=<% $.container %> plan_environment=<% $.plan_environment %>
        on-success: set_status_success
        on-error: process_templates_set_status_failed

      set_status_success:
        on-success: send_message
        publish:
          status: SUCCESS
          message: 'Plan updated.'

      create_swift_rings_backup_plan_set_status_failed:
        on-success: send_message
        publish:
          status: FAILED
          message: <% task(create_swift_rings_backup_plan).result %>

      create_ceph_ansible_fetch_directory_backup_plan_set_status_failed:
        on-success: send_message
        publish:
          status: FAILED
          message: <% task(create_ceph_ansible_fetch_directory_backup_plan).result %>

      does_ceph_ansible_fetch_directory_backup_need_rename_set_status_failed:
        on-success: send_message
        publish:
          status: FAILED
          message: <% task(create_ceph_ansible_fetch_directory_backup_plan).result %>

      clone_git_repo_set_status_failed:
        on-success: send_message
        publish:
          status: FAILED
          message: <% task(clone_git_repo).result %>

      upload_templates_directory_set_status_failed:
        on-success: send_message
        publish:
          status: FAILED
          message: <% task(upload_templates_directory).result %>

      process_templates_set_status_failed:
        on-success: send_message
        publish:
          status: FAILED
          message: <% task(process_templates).result %>

      ensure_passwords_exist_set_status_failed:
        on-success: send_message
        publish:
          status: FAILED
          message: <% task(ensure_passwords_exist).result %>

      container_images_prepare_set_status_failed:
        on-success: send_message
        publish:
          status: FAILED
          message: <% task(container_images_prepare).result %>

      send_message:
        workflow: tripleo.messaging.v1.send
        input:
          queue_name: <% $.queue_name %>
          type: <% execution().name %>
          status: <% $.status %>
          execution: <% execution() %>
          plan_name: <% $.container %>
          message: <% $.get('message', '') %>

  delete_deployment_plan:
    description: >
      Deletes a plan by deleting the container matching plan_name. It will
      not delete the plan if a stack exists with the same name.

    tags:
      - tripleo-common-managed

    input:
      - container: overcloud
      - queue_name: tripleo

    tasks:
      delete_plan:
        action: tripleo.plan.delete container=<% $.container %>
        on-complete: send_message
        publish-on-error:
          status: FAILED
          message: <% task().result %>
        publish:
          status: SUCCESS
          message: <% task().result %>

      send_message:
        workflow: tripleo.messaging.v1.send
        input:
          queue_name: <% $.queue_name %>
          type: <% execution().name %>
          status: <% $.status %>
          execution: <% execution() %>
          plan_name: <% $.container %>
          message: <% $.get('message', '') %>

  get_passwords:
    description: Retrieves passwords for a given plan
    input:
      - container
      - queue_name: tripleo

    tags:
      - tripleo-common-managed

    tasks:

      verify_container_exists:
        workflow: tripleo.swift.v1.container_exists container=<% $.container %>
        on-success: get_environment_passwords
        publish-on-error:
          status: FAILED
          message: <% task().result %>
        on-error: send_message

      get_environment_passwords:
        action: tripleo.parameters.get_passwords container=<% $.container %>
        on-success: get_passwords_set_status_success
        on-error: get_passwords_set_status_failed

      get_passwords_set_status_success:
        on-success: send_message
        publish:
          status: SUCCESS
          message: <% task(get_environment_passwords).result %>

      get_passwords_set_status_failed:
        on-success: send_message
        publish:
          status: FAILED
          message: <% task(get_environment_passwords).result %>

      send_message:
        workflow: tripleo.messaging.v1.send
        input:
          queue_name: <% $.queue_name %>
          type: <% execution().name %>
          status: <% $.status %>
          execution: <% execution() %>
          plan_name: <% $.container %>
          message: <% $.get('message', '') %>

  rotate_passwords:
    description: Rotate passwords for a given plan
    input:
      - container
      - queue_name: tripleo
      - password_list: []

    tags:
      - tripleo-common-managed

    tasks:

      verify_container_exists:
        action: swift.head_container container=<% $.container %>
        publish-on-error:
          status: FAILED
          message: <% task().result %>
        on-success: rotate_environment_passwords
        on-error: send_message

      rotate_environment_passwords:
        action: tripleo.parameters.generate_passwords
        input:
          container: <% $.container %>
          rotate_passwords: true
          rotate_pw_list: <% $.password_list %>
        publish:
          status: SUCCESS
          message: <% task().result %>
        publish-on-error:
          status: FAILED
          message: <% task().result %>
        on-complete: send_message

      send_message:
        workflow: tripleo.messaging.v1.send
        input:
          queue_name: <% $.queue_name %>
          type: <% execution().name %>
          status: <% $.status %>
          execution: <% execution() %>
          plan_name: <% $.container %>
          message: <% $.get('message', '') %>

  export_deployment_plan:
    description: Creates an export tarball for a given plan
    input:
      - plan
      - queue_name: tripleo

    tags:
      - tripleo-common-managed

    tasks:

      export_plan:
        action: tripleo.plan.export
        input:
          plan: <% $.plan %>
          delete_after: 3600
          exports_container: "plan-exports"
        on-success: create_tempurl
        on-error: export_plan_set_status_failed

      create_tempurl:
        action: tripleo.swift.tempurl
        on-success: set_status_success
        on-error: create_tempurl_set_status_failed
        input:
          container: "plan-exports"
          obj: "<% $.plan %>.tar.gz"
          valid: 3600

      set_status_success:
        on-success: send_message
        publish:
          status: SUCCESS
          message: <% task(create_tempurl).result %>
          tempurl: <% task(create_tempurl).result %>

      export_plan_set_status_failed:
        on-success: send_message
        publish:
          status: FAILED
          message: <% task(export_plan).result %>

      create_tempurl_set_status_failed:
        on-success: send_message
        publish:
          status: FAILED
          message: <% task(create_tempurl).result %>

      send_message:
        workflow: tripleo.messaging.v1.send
        input:
          queue_name: <% $.queue_name %>
          type: <% execution().name %>
          status: <% $.status %>
          execution: <% execution() %>
          plan_name: <% $.plan %>
          message: <% $.get('message', '') %>
          payload:
            tempurl: <% $.get('tempurl', '') %>

  get_deprecated_parameters:
    description: Gets the list of deprecated parameters in the whole of the plan including nested stack
    input:
      - container: overcloud
      - queue_name: tripleo

    tags:
      - tripleo-common-managed

    tasks:
      get_roles:
        action: tripleo.role.list container=<% $.container %>
        publish:
          role_name_list: <% task().result %>
        on-success:
          - get_flatten_data: <% $.role_name_list %>
          - set_status_failed_get_roles: <% not $.role_name_list %>
        on-error: set_status_failed_on_error_get_roles

      get_flatten_data:
        action: tripleo.parameters.get_flatten container=<% $.container %>
        on-success: get_deprecated_params
        on-error: set_status_failed_get_flatten_data
        publish:
          user_params: <% task().result.environment_parameters %>
          plan_params: <% task().result.heat_resource_tree.parameters.keys() %>
          parameter_groups: <% task().result.heat_resource_tree.resources.values().where( $.get('parameter_groups') ).select($.parameter_groups).flatten() %>
          params_role_specific_tag: <% task().result.heat_resource_tree.parameters.values().where( $.get('tags') and $.get('tags').contains('role_specific') ).select($.name).flatten() %>
          valid_role_name_list: <% let(hr => task().result.heat_resource_tree.parameters) -> $.role_name_list.where(int($hr.get(concat($, 'Count'), {}).get('default', 0)) > 0) %>

      get_deprecated_params:
        on-success: check_if_user_param_has_deprecated
        publish:
          deprecated_params: <% $.parameter_groups.where($.get('label') = 'deprecated').select($.parameters).flatten().distinct() %>

      check_if_user_param_has_deprecated:
        on-success: get_unused_params
        publish:
          deprecated_result: <% let(up => $.user_params) -> $.deprecated_params.select( dict('parameter' => $, 'deprecated' => true, 'user_defined' => $up.keys().contains($)) ) %>

      # Get the list of parameters, which are defined by user via environment files's parameter_default, but not part of the plan definition
      # It may be possible that the parameter will be used by a service, but the service is not part of the plan.
      # In such cases, the parameter will be reported as unused, care should be take to understand whether it is really unused or not.
      get_unused_params:
        on-success: get_user_role_params
        publish:
          unused_params: <% let(plan_params => $.plan_params) ->  $.user_params.keys().where( not $plan_params.contains($) ) %>

      get_user_role_params:
        on-success: is_user_role_specific_input_provided
        with-items: role_name in <% $.valid_role_name_list %>
        concurrency: 1
        action: std.echo output=<% "{}Parameters".format($.role_name) %>
        publish:
          user_provided_role_specific: <% let(param => task().result) -> $.user_params.items().where( $param.contains($[0]) ).select( $[1] ).flatten() %>

      is_user_role_specific_input_provided:
        on-success:
          - find_invalid_role_specific_params: <% $.user_provided_role_specific %>
          - send_message: <% not $.user_provided_role_specific %>

      find_invalid_role_specific_params:
        on-success: send_message
        publish:
          invalid_role_specific: <% let(role_spec => $.params_role_specific_tag) -> $.user_provided_role_specific.sum().keys().where( not $role_spec.contains($) ) %>

      set_status_failed_get_flatten_data:
        on-success: send_message
        publish:
          status: FAILED
          message: <% task(get_flatten_data).result %>

      set_status_failed_get_roles:
        on-success: send_message
        publish:
          status: FAILED
          message: "Unable to determine the list of roles in the deployment plan"

      set_status_failed_on_error_get_roles:
        on-success: send_message
        publish:
          status: FAILED
          message: <% task(get_roles).result %>

      send_message:
        workflow: tripleo.messaging.v1.send
        input:
          queue_name: <% $.queue_name %>
          type: <% execution().name %>
          status: <% $.get('status', 'SUCCESS') %>
          execution: <% execution() %>
          plan_name: <% $.container %>
          message: <% $.get('message', '') %>
          payload:
            deprecated: <% $.get('deprecated_result', []) %>
            unused: <% $.get('unused_params', []) %>
            invalid_role_specific: <% $.get('invalid_role_specific', []) %>

  update_parameters:
    description: >
      Updates plan environment with parameters.

    tags:
      - tripleo-common-managed

    input:
      - container: overcloud
      - parameters
      - key
      - queue_name: tripleo

    tasks:
      update_parameters:
        action: tripleo.parameters.update
        input:
          container: <% $.container %>
          parameters: <% $.parameters %>
          key: <% $.key %>
        on-complete: send_message
        publish-on-error:
          status: FAILED
          message: <% task().result %>
        publish:
          status: SUCCESS
          message: <% task().result %>

      send_message:
        workflow: tripleo.messaging.v1.send
        input:
          queue_name: <% $.queue_name %>
          type: <% execution().name %>
          status: <% $.status %>
          message: <% $.get('message', '') %>
          execution: <% execution() %>
          plan_name: <% $.container %>

  publish_ui_logs_to_swift:
    description: >
      This workflow drains a zaqar queue, and publish its messages into a log
      file in swift.  This workflow is called by cron trigger.

    input:
      - logging_queue_name: tripleo-ui-logging
      - logging_container: tripleo-ui-logs

    tags:
      - tripleo-common-managed

    tasks:

      # We're using a NoOp action to start the workflow.  The recursive nature
      # of the workflow means that Mistral will refuse to execute it because it
      # doesn't know where to begin.
      start:
        on-success: get_messages

      get_messages:
        action: zaqar.claim_messages
        on-success:
          - format_messages: <% task().result.len() > 0 %>
        input:
          queue_name: <% $.logging_queue_name %>
          ttl: 60
          grace: 60
        publish:
          status: SUCCESS
          messages: <% task().result %>
          message_ids: <% task().result.select($.id) %>

      format_messages:
        action: tripleo.logging_to_swift.format_messages
        on-success: upload_to_swift
        input:
          messages: <% $.messages %>
        publish:
          status: SUCCESS
          formatted_messages: <% task().result %>

      upload_to_swift:
        action: tripleo.logging_to_swift.publish_ui_log_to_swift
        on-success: delete_messages
        input:
          logging_data: <% $.formatted_messages %>
          logging_container: <% $.logging_container %>
        publish:
          status: SUCCESS

      delete_messages:
        action: zaqar.delete_messages
        on-success: get_messages
        input:
          queue_name: <% $.logging_queue_name %>
          messages: <% $.message_ids %>
        publish:
          status: SUCCESS

  download_logs:
    description: Creates a tarball with logging data
    input:
      - queue_name: tripleo
      - logging_container: "tripleo-ui-logs"
      - downloads_container: "tripleo-ui-logs-downloads"
      - delete_after: 3600

    tags:
      - tripleo-common-managed

    tasks:

      publish_logs:
        workflow: tripleo.plan_management.v1.publish_ui_logs_to_swift
        on-success: check_if_logging_container_present
        on-error: publish_logs_set_status_failed

      check_if_logging_container_present:
        workflow: tripleo.swift.v1.container_exists
        input:
          container: <% $.logging_container %>
        on-error: set_container_empty_error
        on-success: check_if_logging_files_present

      check_if_logging_files_present:
        action: swift.get_container
        input:
          container: <% $.logging_container %>
        on-success:
          - prepare_log_download: <% task().result[1].len() > 0 %>
          - set_container_empty_error: <% task().result[1].len() = 0 %>
        on-error: set_container_empty_error

      set_container_empty_error:
        on-success: send_message
        publish:
          status: FAILED
          message: "There are no logs to download."

      prepare_log_download:
        action: tripleo.logging_to_swift.prepare_log_download
        input:
          logging_container: <% $.logging_container %>
          downloads_container: <% $.downloads_container %>
          delete_after: <% $.delete_after %>
        on-success: create_tempurl
        on-error: download_logs_set_status_failed
        publish:
          filename: <% task().result %>

      create_tempurl:
        action: tripleo.swift.tempurl
        on-success: set_status_success
        on-error: create_tempurl_set_status_failed
        input:
          container: <% $.downloads_container %>
          obj: <% $.filename %>
          valid: 3600
        publish:
          tempurl: <% task().result %>

      set_status_success:
        on-success: send_message
        publish:
          status: SUCCESS
          message: <% task(create_tempurl).result %>
          tempurl: <% task(create_tempurl).result %>

      publish_logs_set_status_failed:
        on-success: send_message
        publish:
          status: FAILED
          message: <% task(publish_logs).result %>

      download_logs_set_status_failed:
        on-success: send_message
        publish:
          status: FAILED
          message: <% task(prepare_log_download).result %>

      create_tempurl_set_status_failed:
        on-success: send_message
        publish:
          status: FAILED
          message: <% task(create_tempurl).result %>

      send_message:
        workflow: tripleo.messaging.v1.send
        input:
          queue_name: <% $.queue_name %>
          type: <% execution().name %>
          status: <% $.status %>
          execution: <% execution() %>
          message: <% $.get('message', '') %>
          payload:
            tempurl: <% $.get('tempurl', '') %>

  list_roles:
    description: Retrieve the roles_data.yaml and return a usable object

    input:
      - container: overcloud
      - roles_data_file: 'roles_data.yaml'
      - queue_name: tripleo

    output:
      roles_data: <% $.roles_data %>

    tags:
      - tripleo-common-managed

    tasks:
      get_roles_data:
        action: swift.get_object
        input:
          container: <% $.container %>
          obj: <% $.roles_data_file %>
        publish:
          roles_data: <% yaml_parse(task().result.last()) %>
          status: SUCCESS
        on-success: send_message
        publish-on-error:
          status: FAILED
          message: <% task().result %>
        on-error: send_message

      send_message:
        workflow: tripleo.messaging.v1.send
        input:
          queue_name: <% $.queue_name %>
          type: <% execution().name %>
          status: <% $.status %>
          execution: <% execution() %>
          plan_name: <% $.container %>
          message: <% $.get('message', '') %>
          payload:
            roles_data: <% $.get('roles_data', {}) %>

  list_available_networks:
    input:
      - container
      - queue_name: tripleo

    output:
      available_networks: <% $.available_networks %>

    tags:
      - tripleo-common-managed

    tasks:
      get_network_file_names:
        action: swift.get_container
        input:
          container: <% $.container %>
        publish:
          network_names: <% task().result[1].where($.name.startsWith('networks/')).where($.name.endsWith('.yaml')).name %>
        on-success: get_network_files
        on-error: send_message
        publish-on-error:
          status: FAILED
          message: <% task().result %>

      get_network_files:
        with-items: network_name in <% $.network_names %>
        action: swift.get_object
        on-success: transform_output
        on-error: send_message
        input:
          container: <% $.container %>
          obj: <% $.network_name %>
        publish:
          status: SUCCESS
          available_yaml_networks: <% task().result.select($[1]) %>
        publish-on-error:
          status: FAILED
          message: <% task().result %>

      transform_output:
        publish:
          status: SUCCESS
          available_networks: <% yaml_parse($.available_yaml_networks.join("\n")) %>
        publish-on-error:
          status: FAILED
          message: <% task().result %>
        on-complete: send_message

      send_message:
        workflow: tripleo.messaging.v1.send
        input:
          queue_name: <% $.queue_name %>
          type: <% execution().name %>
          status: <% $.status %>
          execution: <% execution() %>
          plan_name: <% $.container %>
          message: <% $.get('message', '') %>
          payload:
            available_networks: <% $.get('available_networks', []) %>

  list_networks:
    input:
      - container: 'overcloud'
      - network_data_file: 'network_data.yaml'
      - queue_name: tripleo

    output:
      network_data: <% $.network_data %>

    tags:
      - tripleo-common-managed

    tasks:
      get_networks:
        action: swift.get_object
        input:
          container: <% $.container %>
          obj: <% $.network_data_file %>
        on-success: send_message
        publish:
          network_data: <% yaml_parse(task().result.last()) %>
          status: SUCCESS
          message: <% task().result %>
        on-error: send_message
        publish-on-error:
          status: FAILED
          message: <% task().result %>

      send_message:
        workflow: tripleo.messaging.v1.send
        input:
          queue_name: <% $.queue_name %>
          type: <% execution().name %>
          status: <% $.status %>
          execution: <% execution() %>
          plan_name: <% $.container %>
          message: <% $.get('message', '') %>
          payload:
            network_data: <% $.get('network_data', {}) %>

  validate_network_files:
    description: Validate network files exist
    input:
      - container: overcloud
      - network_data
      - queue_name: tripleo

    output:
      network_data: <% $.network_data %>

    tags:
      - tripleo-common-managed

    tasks:
      get_network_names:
        publish:
          network_names_lower: <% $.network_data.where($.containsKey('name_lower')).name_lower %>
          network_names: <% $.network_data.where(not $.containsKey('name_lower')).name %>
        on-success: validate_networks

      validate_networks:
        with-items: network in <% $.network_names_lower.concat($.network_names) %>
        action: swift.head_object
        input:
          container: <% $.container %>
          obj: network/<% $.network.toLower() %>.yaml
        publish:
          status: SUCCESS
          message: <% task().result %>
        on-success: send_message
        publish-on-error:
          status: FAILED
          message: <% task().result %>

      send_message:
        workflow: tripleo.messaging.v1.send
        input:
          queue_name: <% $.queue_name %>
          type: <% execution().name %>
          status: <% $.status %>
          execution: <% execution() %>
          plan_name: <% $.container %>
          message: <% $.message %>

  validate_networks:
    description: Validate network files were generated properly and exist
    input:
      - container: 'overcloud'
      - network_data_file: 'network_data.yaml'
      - queue_name: tripleo

    output:
      network_data: <% $.network_data %>

    tags:
      - tripleo-common-managed

    tasks:
      get_network_data:
        workflow: list_networks
        input:
          container: <% $.container %>
          network_data_file: <% $.network_data_file %>
          queue_name: <% $.queue_name %>
        publish:
          network_data: <% task().result.network_data %>
        on-success: validate_networks
        publish-on-error:
          status: FAILED
          message: <% task().result %>
        on-error:
          send_message

      validate_networks:
        workflow: validate_network_files
        input:
          container: <% $.container %>
          network_data: <% $.network_data %>
          queue_name: <% $.queue_name %>
        publish:
          status: SUCCESS
          message: <% task().result %>
        on-success: send_message
        publish-on-error:
          status: FAILED
          message: <% task().result %>
        on-error: send_message

      send_message:
        workflow: tripleo.messaging.v1.send
        input:
          queue_name: <% $.queue_name %>
          type: <% execution().name %>
          status: <% $.status %>
          execution: <% execution() %>
          plan_name: <% $.container %>
          message: <% $.get('message', '') %>
          payload:
            network_data: <% $.get('network_data', {}) %>

  validate_roles:
    description: Vaildate roles data exists and is parsable

    input:
      - container: overcloud
      - roles_data_file: 'roles_data.yaml'
      - queue_name: tripleo

    output:
      roles_data: <% $.roles_data %>

    tags:
      - tripleo-common-managed

    tasks:
      get_roles_data:
        workflow: list_roles
        input:
          container: <% $.container %>
          roles_data_file: <% $.roles_data_file %>
          queue_name: <% $.queue_name %>
        publish:
          roles_data: <% task().result.roles_data %>
          status: SUCCESS
        on-success: send_message
        publish-on-error:
          status: FAILED
          message: <% task().result %>
        on-error:
          send_message

      send_message:
        workflow: tripleo.messaging.v1.send
        input:
          queue_name: <% $.queue_name %>
          type: <% execution().name %>
          status: <% $.status %>
          execution: <% execution() %>
          plan_name: <% $.container %>
          message: <% $.get('message', '') %>
          payload:
            roles_data: <% $.get('roles_data', '') %>

  _validate_networks_from_roles:
    description: Internal workflow for validating a network exists from a role

    input:
      - container: overcloud
      - defined_networks
      - networks_in_roles
      - queue_name: tripleo

    tags:
      - tripleo-common-managed

    tasks:
      validate_network_in_network_data:
        publish:
          networks_found: <% $.networks_in_roles.toSet().intersect($.defined_networks.toSet()) %>
          networks_not_found: <% $.networks_in_roles.toSet().difference($.defined_networks.toSet()) %>
        on-success:
          - network_not_found: <% $.networks_not_found %>
          - send_message: <% not $.networks_not_found %>

      network_not_found:
        publish:
          message: <% "Some networks in roles are not defined, {0}".format($.networks_not_found.join(', ')) %>
          status: FAILED
        on-success: send_message

      send_message:
        workflow: tripleo.messaging.v1.send
        input:
          queue_name: <% $.queue_name %>
          type: <% execution().name %>
          status: <% $.get('status', 'SUCCESS') %>
          execution: <% execution() %>
          plan_name: <% $.container %>
          message: <% $.get('message', '') %>

  validate_roles_and_networks:
    description: Vaidate that roles and network data are valid

    input:
      - container: overcloud
      - roles_data_file: 'roles_data.yaml'
      - network_data_file: 'network_data.yaml'
      - queue_name: tripleo

    output:
      roles_data: <% $.roles_data %>
      network_data: <% $.network_data %>

    tags:
      - tripleo-common-managed

    tasks:
      validate_network_data:
        workflow: validate_networks
        input:
          container: <% $.container %>
          network_data_file: <% $.network_data_file %>
          queue_name: <% $.queue_name %>
        publish:
          network_data: <% task().result.network_data %>
        on-success: validate_roles_data
        publish-on-error:
          status: FAILED
          message: <% task().result %>
        on-error: send_message

      validate_roles_data:
        workflow: validate_roles
        input:
          container: <% $.container %>
          roles_data_file: <% $.roles_data_file %>
          queue_name: <% $.queue_name %>
        publish:
          roles_data: <% task().result.roles_data %>
          role_networks_data: <% task().result.roles_data.networks %>
          networks_in_roles: <% task().result.roles_data.networks.flatten().distinct() %>
        on-success: validate_roles_and_networks
        publish-on-error:
          status: FAILED
          message: <% task().result %>
        on-error: send_message

      validate_roles_and_networks:
        workflow: _validate_networks_from_roles
        input:
          container: <% $.container %>
          defined_networks: <% $.network_data.name %>
          networks_in_roles: <% $.networks_in_roles %>
          queue_name: <% $.queue_name %>
        publish:
          status: SUCCESS
        on-success: send_message
        publish-on-error:
          status: FAILED
          message: <% task().result.message %>
        on-error: send_message

      send_message:
        workflow: tripleo.messaging.v1.send
        input:
          queue_name: <% $.queue_name %>
          type: <% execution().name %>
          status: <% $.status %>
          execution: <% execution() %>
          plan_name: <% $.container %>
          message: <% $.get('message', '') %>
          payload:
            roles_data: <% $.get('roles_data', {}) %>
            network_data: <% $.get('network_data', {}) %>

  list_sample_plans:
    input:
      - container: overcloud
      - queue_name: tripleo

    output:
      available_plans: <% $.available_plans %>

    tags:
      - tripleo-common-managed

    tasks:
      get_available_plans:
        action: swift.get_container
        input:
          container: <% $.container %>
        publish:
          plan_files: <% task().result[1].where($.name.startsWith('plan-samples/')).where($.name.endsWith('plan-environment.yaml')).name %>
        on-success: publish_available_plans
        on-error: send_message
        publish-on-error:
          status: FAILED
          message: <% task().result %>

      publish_available_plans:
        workflow: tripleo.plan_management.v1._get_sample_plan
        with-items: plan_file in <% $.plan_files %>
        input:
          plan_file: <% $.plan_file %>
        publish:
          status: SUCCESS
          available_plans: <% task().result %>
        publish-on-error:
          status: FAILED
          message: <% task().result %>
        on-complete: send_message

      send_message:
        workflow: tripleo.messaging.v1.send
        input:
          queue_name: <% $.queue_name %>
          type: <% execution().name %>
          status: <% $.status %>
          execution: <% execution() %>
          plan_name: <% $.container %>
          message: <% $.get('message', '') %>
          payload:
            available_plans: <% $.get('available_plans', []) %>

  _get_sample_plan:
    input:
      - container: overcloud
      - plan_file

    tags:
      - tripleo-common-managed

    tasks:
      get_plan_object:
        action: swift.get_object
        input:
          container: <% $.container %>
          obj: <% $.plan_file %>
        publish:
          sample_plan_name:  <% $.plan_file.split("/")[1] %>
          plan_file: <% $.plan_file %>
          plan_contents: <% task().result[1] %>

  select_sample_plan:
    input:
      - container: overcloud
      - sample_plan_name: openstack
      - queue_name: tripleo

    tags:
      - tripleo-common-managed

    tasks:
      get_plan_file_names:
        action: swift.get_container
        input:
          container: <% $.container %>
        on-success: copy_files_to_root
        on-error: send_message
        publish:
          plan_files: <% let(root => $) -> task().result[1].where($.name.startsWith("plan-samples/{}/".format($root.sample_plan_name))).where($.name.endsWith('.yaml')).name %>
        publish-on-error:
          status: FAILED
          message: <% task().result %>

      copy_files_to_root:
        with-items: plan_file in <% $.plan_files %>
        workflow: tripleo.plan_management.v1._copy_object_to_root
        input:
          container: <% $.container %>
          plan_name: <% $.sample_plan_name %>
          object_name: <% $.plan_file %>
        publish:
          status: SUCCESS
        publish-on-error:
          status: FAILED
          message: <% task().result %>
        on-complete: send_message

      send_message:
        workflow: tripleo.messaging.v1.send
        input:
          queue_name: <% $.queue_name %>
          type: <% execution().name %>
          status: <% $.status %>
          execution: <% execution() %>
          plan_name: <% $.container %>
          message: <% $.get('message', '') %>

  _copy_object_to_root:
    input:
      - container
      - plan_name
      - object_name

    tags:
      - tripleo-common-managed

    tasks:
      # We skip any files where the root object already exists
      check_for_existing_object:
        workflow: tripleo.swift.v1.object_exists
        input:
          container: <% $.container %>
          object: <% $.object_name.split('/').last() %>
        on-error: copy_object

      copy_object:
        action: swift.copy_object
        input:
          container: <% $.container %>
          obj: <% $.object_name %>
          destination: <% list($.container, $.object_name.split('/').last()).join('/') %>

  list_available_roles:
    input:
      - container: overcloud
      - queue_name: tripleo

    output:
      available_roles: <% $.available_roles %>

    tags:
      - tripleo-common-managed

    tasks:
      get_plan_role_tags:
        action: swift.get_object
        input:
          container: <% $.container %>
          obj: plan-environment.yaml
        publish:
          role_tags: <% yaml_parse(task().result.last()).get(role_tags) %>
        on-success: get_role_file_names
        on-error: send_message
        publish-on-error:
          status: FAILED
          message: <% task().result %>

      get_role_file_names:
        action: swift.get_container
        input:
          container: <% $.container %>
        publish:
          role_names: <% task().result[1].where($.name.startsWith('roles/')).where($.name.endsWith('.yaml')).name %>
        on-success: get_role_files
        on-error: send_message
        publish-on-error:
          status: FAILED
          message: <% task().result %>

      get_role_files:
        with-items: role_name in <% $.role_names %>
        action: swift.get_object
        on-success: transform_output
        on-error: send_message
        input:
          container: <% $.container %>
          obj: <% $.role_name %>
        publish:
          status: SUCCESS
          available_yaml_roles: <% task().result.select($[1]) %>
        publish-on-error:
          status: FAILED
          message: <% task().result %>

      transform_output:
        publish:
          status: SUCCESS
          available_roles: <% let(root => $, roles => yaml_parse($.available_yaml_roles.join("\n"))) -> ($root.role_tags = null and $roles or $roles.where($root.role_tags.toSet().intersect($.get(tags, []).toSet()))) %>
        publish-on-error:
          status: FAILED
          message: <% task().result %>
        on-complete: send_message

      send_message:
        workflow: tripleo.messaging.v1.send
        input:
          queue_name: <% $.queue_name %>
          type: <% execution().name %>
          status: <% $.status %>
          execution: <% execution() %>
          plan_name: <% $.container %>
          message: <% $.get('message', '') %>
          payload:
            available_roles: <% $.get('available_roles', []) %>

  update_roles:
    description: >
      takes data in json format validates its contents and persists them in
      roles_data.yaml, after successful update, templates are regenerated.
    input:
      - container
      - roles
      - roles_data_file: 'roles_data.yaml'
      - replace_all: false
      - queue_name: tripleo
    tags:
      - tripleo-common-managed
    tasks:
      get_available_roles:
        workflow: list_available_roles
        input:
          container: <% $.container %>
          queue_name: <% $.queue_name%>
        publish:
          available_roles: <% task().result.available_roles %>
        on-success: validate_input
        on-error: send_message
        publish-on-error:
          status: FAILED
          message: <% task().result %>

      validate_input:
        description: >
          validate the format of input (verify that each role in input has the
          required attributes set. check README in roles directory in t-h-t),
          validate that roles in input exist in roles directory in t-h-t
        action: tripleo.plan.validate_roles
        input:
          container: <% $.container %>
          roles: <% $.roles %>
          available_roles: <% $.available_roles %>
        on-success: get_network_data
        on-error: send_message
        publish-on-error:
          status: FAILED
          message: <% task().result %>

      get_network_data:
        workflow: list_networks
        input:
          container: <% $.container %>
          queue_name: <% $.queue_name %>
        publish:
          network_data: <% task().result.network_data %>
        on-success: validate_network_names
        publish-on-error:
          status: FAILED
          message: <% task().result %>
        on-error: send_message

      validate_network_names:
        description: >
          validate that Network names assigned to Role exist in
          network-data.yaml object in Swift container
        workflow: _validate_networks_from_roles
        input:
          container: <% $.container %>
          defined_networks: <% $.network_data.name %>
          networks_in_roles: <% $.roles.networks.flatten().distinct() %>
          queue_name: <% $.queue_name %>
        on-success: get_current_roles
        on-error: send_message
        publish-on-error:
          status: FAILED
          message: <% task().result.message %>

      get_current_roles:
        workflow: list_roles
        input:
          container: <% $.container %>
          roles_data_file: <% $.roles_data_file %>
          queue_name: <% $.queue_name %>
        publish:
            current_roles: <% task().result.roles_data %>
        on-success: update_roles_data
        on-error: send_message
        publish-on-error:
          status: FAILED
          message: <% task().result %>

      update_roles_data:
        description: >
          update roles_data.yaml object in Swift with roles from workflow input
        action: tripleo.plan.update_roles
        input:
          container: <% $.container %>
          roles: <% $.roles %>
          current_roles: <% $.current_roles %>
          replace_all: <% $.replace_all %>
        publish:
          updated_roles_data: <% task().result.roles %>
        on-success: update_roles_data_in_swift
        on-error: send_message
        publish-on-error:
          status: FAILED
          message: <% task().result %>

      update_roles_data_in_swift:
        description: >
          update roles_data.yaml object in Swift with data from workflow input
        action: swift.put_object
        input:
          container: <% $.container %>
          obj: <% $.roles_data_file %>
          contents: <% yaml_dump($.updated_roles_data) %>
        on-success: regenerate_templates
        publish-on-error:
          status: FAILED
          message: <% task().result %>
        on-error: send_message

      regenerate_templates:
        action: tripleo.templates.process container=<% $.container %>
        on-success: get_updated_roles
        on-error: send_message
        publish-on-error:
          status: FAILED
          message: <% task().result %>

      get_updated_roles:
        workflow: list_roles
        input:
          container: <% $.container %>
          roles_data_file:  <% $.roles_data_file %>
        publish:
            updated_roles: <% task().result.roles_data %>
            status: SUCCESS
        on-complete: send_message
        publish-on-error:
          status: FAILED
          message: <% task().result %>

      send_message:
        workflow: tripleo.messaging.v1.send
        input:
          queue_name: <% $.queue_name %>
          type: <% execution().name %>
          status: <% $.status %>
          execution: <% execution() %>
          plan_name: <% $.container %>
          message: <% $.get('message', '') %>
          payload:
            updated_roles: <% $.get('updated_roles', []) %>

  select_roles:
    description: >
      takes a list of role names as input and populates roles_data.yaml in
      container in Swift with respective roles from 'roles directory'
    input:
      - container
      - role_names
      - roles_data_file: 'roles_data.yaml'
      - replace_all: true
      - queue_name: tripleo
    tags:
      - tripleo-common-managed
    tasks:

      get_available_roles:
        workflow: list_available_roles
        input:
          container: <% $.container %>
          queue_name: <% $.queue_name %>
        publish:
          available_roles: <% task().result.available_roles %>
        on-success: get_current_roles
        on-error: send_message
        publish-on-error:
          status: FAILED
          message: <% task().result %>

      get_current_roles:
        workflow: list_roles
        input:
          container: <% $.container %>
          roles_data_file: <% $.roles_data_file %>
          queue_name: <% $.queue_name %>
        publish:
          current_roles: <% task().result.roles_data %>
        on-success: gather_roles
        on-error: send_message
        publish-on-error:
          status: FAILED
          message: <% task().result %>

      gather_roles:
        description: >
          for each role name from the input, check if it exists in
          roles_data.yaml, if yes, use that role definition, if not, get the
          role definition from roles directory. Use the gathered roles
          definitions as input to updateRolesWorkflow - this ensures
          configuration of the roles which are already in roles_data.yaml
          will not get overridden by data from roles directory
        action: tripleo.plan.gather_roles
        input:
          role_names: <% $.role_names %>
          current_roles: <% $.current_roles %>
          available_roles: <% $.available_roles %>
        publish:
          gathered_roles: <% task().result.gathered_roles %>
        on-success: call_update_roles_workflow
        on-error: send_message
        publish-on-error:
          status: FAILED
          message: <% task().result %>

      call_update_roles_workflow:
        workflow: update_roles
        input:
          container: <% $.container %>
          roles: <% $.gathered_roles %>
          roles_data_file: <% $.roles_data_file %>
          replace_all: <% $.replace_all %>
          queue_name: <% $.queue_name %>
        on-complete: send_message
        publish:
          selected_roles: <% task().result.updated_roles %>
          status: SUCCESS
        publish-on-error:
          status: FAILED
          message: <% task().result %>

      send_message:
        workflow: tripleo.messaging.v1.send
        input:
          queue_name: <% $.queue_name %>
          type: <% execution().name %>
          status: <% $.status %>
          execution: <% execution() %>
          plan_name: <% $.container %>
          message: <% $.get('message', '') %>
          payload:
            selected_roles: <% $.get('selected_roles', []) %>

  list_plans:
    description: >
      This workflow lists all deployment plans residing in the undercloud.  A
      deployment plan consists of a container marked with metadata
      'x-container-meta-usage-tripleo'.

    tags:
      - tripleo-common-managed

    input:
      - queue_name: tripleo

    output:
      plan_list: <% $.plans %>

    tasks:
      list_plans:
        action: tripleo.plan.list
        on-complete: send_message
        publish:
          status: SUCCESS
          message: <% task().result %>
          plans: <% task().result %>
        publish-on-error:
          status: FAILED
          message: <% task().result %>

      send_message:
        workflow: tripleo.messaging.v1.send
        input:
          queue_name: <% $.queue_name %>
          type: <% execution().name %>
          status: <% $.status %>
          execution: <% execution() %>
          message: <% $.get('message', '') %>
          payload:
            plans: <% $.get('plans', []) %>
