heat_template_version: 2014-10-16

description: >
  This template will boot a Mesos cluster with one or more masters
  (as specified by number_of_masters, default is 1) and one or more slaves
  (as specified by the number_of_slaves parameter, which
  defaults to 1).

parameters:

  ssh_key_name:
    type: string
    description: name of ssh key to be provisioned on our server

  external_network:
    type: string
    description: uuid/name of a network to use for floating ip addresses
    default: public

  fixed_network:
    type: string
    description: uuid/name of an existing network to use to provision machines
    default: ""

  fixed_subnet:
    type: string
    description: uuid/name of an existing subnet to use to provision machines
    default: ""

  server_image:
    type: string
    default: ubuntu-mesos
    description: glance image used to boot the server

  master_flavor:
    type: string
    default: m1.small
    description: flavor to use when booting the master server

  slave_flavor:
    type: string
    default: m1.small
    description: flavor to use when booting the slave server

  dns_nameserver:
    type: string
    description: address of a dns nameserver reachable in your environment
    default: 8.8.8.8

  number_of_slaves:
    type: number
    description: how many mesos slaves to spawn initially
    default: 1

  fixed_network_cidr:
    type: string
    description: network range for fixed ip network
    default: 10.0.0.0/24

  wait_condition_timeout:
    type: number
    description: >
      timeout for the Wait Conditions
    default: 6000

  cluster_name:
    type: string
    description: human readable name for the mesos cluster
    default: my-cluster

  executor_registration_timeout:
    type: string
    description: >
      Amount of time to wait for an executor to register with the slave before
      considering it hung and shutting it down
    default: 5mins

  number_of_masters:
    type: number
    description: how many mesos masters to spawn initially
    default: 1

  http_proxy:
    type: string
    description: http proxy address for docker
    default: ""

  https_proxy:
    type: string
    description: https proxy address for docker
    default: ""

  no_proxy:
    type: string
    description: no proxies for docker
    default: ""

  trustee_domain_id:
    type: string
    description: domain id of the trustee
    default: ""

  trustee_user_id:
    type: string
    description: user id of the trustee
    default: ""

  trustee_username:
    type: string
    description: username of the trustee
    default: ""

  trustee_password:
    type: string
    description: password of the trustee
    default: ""
    hidden: true

  trust_id:
    type: string
    description: id of the trust which is used by the trustee
    default: ""
    hidden: true

  region_name:
    type: string
    description: a logically separate section of the cluster

  username:
    type: string
    description: user name

  password:
    type: string
    description: >
      user password, not set in current implementation, only used to
      fill in for Mesos config file
    default:
      password
    hidden: true

  tenant_name:
    type: string
    description: >
      tenant_name is used to isolate access to Compute resources

  volume_driver:
    type: string
    description: volume driver to use for container storage
    default: ""

  domain_name:
    type: string
    description: >
      domain is to define the administrative boundaries for management
      of Keystone entities

  rexray_preempt:
    type: string
    description: >
      enables any host to take control of a volume irrespective of whether
      other hosts are using the volume
    default: "false"

  auth_url:
    type: string
    description: url for keystone

  mesos_slave_isolation:
    type: string
    description: >
      Isolation mechanisms to use, e.g., `posix/cpu,posix/mem`, or
      `cgroups/cpu,cgroups/mem`, or network/port_mapping (configure with flag:
      `--with-network-isolator` to enable), or `cgroups/devices/gpus/nvidia`
      for nvidia specific gpu isolation (configure with flag: `--enable-nvidia
      -gpu-support` to enable), or `external`, or load an alternate isolator
      module using the `--modules` flag. Note that this flag is only relevant
      for the Mesos Containerizer.
    default: ""

  mesos_slave_work_dir:
    type: string
    description: directory path to place framework work directories
    default: ""

  mesos_slave_image_providers:
    type: string
    description: >
      Comma separated list of supported image providers e.g.,
      APPC,DOCKER
    default: ""

  mesos_slave_executor_env_variables:
    type: string
    description: >
      JSON object representing the environment variables that should be passed
      to the executor, and thus subsequently task(s). By default the executor,
      executor will inherit the slave's environment variables.
    default: ""

  slaves_to_remove:
    type: comma_delimited_list
    description: >
      List of slaves to be removed when doing an update. Individual slave may
      be referenced several ways: (1) The resource name (e.g.['1', '3']),
      (2) The private IP address ['10.0.0.4', '10.0.0.6']. Note: the list should
      be empty when doing a create.
    default: []

resources:

  ######################################################################
  #
  # network resources.  allocate a network and router for our server.
  #

  network:
    type: ../../common/templates/network.yaml
    properties:
      existing_network: {get_param: fixed_network}
      existing_subnet: {get_param: fixed_subnet}
      private_network_cidr: {get_param: fixed_network_cidr}
      dns_nameserver: {get_param: dns_nameserver}
      external_network: {get_param: external_network}

  api_lb:
    type: ../../common/templates/lb.yaml
    properties:
      fixed_subnet: {get_attr: [network, fixed_subnet]}
      external_network: {get_param: external_network}
      protocol: HTTP
      port: 8080

  ######################################################################
  #
  # security groups.  we need to permit network traffic of various
  # sorts.
  #

  secgroup_master:
    type: OS::Neutron::SecurityGroup
    properties:
      rules:
        - protocol: icmp
        - protocol: tcp
          port_range_min: 22
          port_range_max: 22
        - protocol: tcp
          remote_mode: remote_group_id
        - protocol: tcp
          port_range_min: 5050
          port_range_max: 5050
        - protocol: tcp
          port_range_min: 8080
          port_range_max: 8080

  secgroup_slave_all_open:
    type: OS::Neutron::SecurityGroup
    properties:
      rules:
        - protocol: icmp
        - protocol: tcp
        - protocol: udp

  ######################################################################
  #
  # Master SoftwareConfig.
  #

  write_params_master:
    type: OS::Heat::SoftwareConfig
    properties:
      group: script
      config: {get_file: fragments/write-heat-params-master.sh}
      inputs:
        - name: MESOS_MASTERS_IPS
          type: String
        - name: CLUSTER_NAME
          type: String
        - name: QUORUM
          type: String
        - name: HTTP_PROXY
          type: String
        - name: HTTPS_PROXY
          type: String
        - name: NO_PROXY
          type: String

  configure_master:
    type: OS::Heat::SoftwareConfig
    properties:
      group: script
      config: {get_file: fragments/configure-mesos-master.sh}

  add_proxy_master:
    type: OS::Heat::SoftwareConfig
    properties:
      group: script
      config: {get_file: fragments/add-proxy.sh}

  start_services_master:
    type: OS::Heat::SoftwareConfig
    properties:
      group: script
      config: {get_file: fragments/start-services-master.sh}

  ######################################################################
  #
  # Master SoftwareDeployment.
  #

  write_params_master_deployment:
    type: OS::Heat::SoftwareDeploymentGroup
    properties:
      config: {get_resource: write_params_master}
      servers: {get_attr: [mesos_masters, attributes, mesos_server_id]}
      input_values:
        MESOS_MASTERS_IPS: {list_join: [' ', {get_attr: [mesos_masters, mesos_master_ip]}]}
        CLUSTER_NAME: {get_param: cluster_name}
        NUMBER_OF_MASTERS: {get_param: number_of_masters}
        HTTP_PROXY: {get_param: http_proxy}
        HTTPS_PROXY: {get_param: https_proxy}
        NO_PROXY: {get_param: no_proxy}

  configure_master_deployment:
    type: OS::Heat::SoftwareDeploymentGroup
    depends_on:
      - write_params_master_deployment
    properties:
      config: {get_resource: configure_master}
      servers: {get_attr: [mesos_masters, attributes, mesos_server_id]}

  add_proxy_master_deployment:
    type: OS::Heat::SoftwareDeploymentGroup
    depends_on:
      - configure_master_deployment
    properties:
      config: {get_resource: add_proxy_master}
      servers: {get_attr: [mesos_masters, attributes, mesos_server_id]}

  start_services_master_deployment:
    type: OS::Heat::SoftwareDeploymentGroup
    depends_on:
      - add_proxy_master_deployment
    properties:
      config: {get_resource: start_services_master}
      servers: {get_attr: [mesos_masters, attributes, mesos_server_id]}

  ######################################################################
  #
  # resources that expose the IPs of either the mesos master or a given
  # LBaaS pool depending on whether LBaaS is enabled for the bay.
  #

  api_address_lb_switch:
    type: Magnum::ApiGatewaySwitcher
    properties:
      pool_public_ip: {get_attr: [api_lb, floating_address]}
      pool_private_ip: {get_attr: [api_lb, address]}
      master_public_ip: {get_attr: [mesos_masters, resource.0.mesos_master_external_ip]}
      master_private_ip: {get_attr: [mesos_masters, resource.0.mesos_master_ip]}

  ######################################################################
  #
  # Mesos masters. This is a resource group that will create
  # <number_of_masters> masters.
  #

  mesos_masters:
    type: OS::Heat::ResourceGroup
    depends_on:
      - network
    properties:
      count: {get_param: number_of_masters}
      resource_def:
        type: mesosmaster.yaml
        properties:
          ssh_key_name: {get_param: ssh_key_name}
          server_image: {get_param: server_image}
          master_flavor: {get_param: master_flavor}
          external_network: {get_param: external_network}
          fixed_network: {get_attr: [network, fixed_network]}
          fixed_subnet: {get_attr: [network, fixed_subnet]}
          secgroup_mesos_id: {get_resource: secgroup_master}
          api_pool_id: {get_attr: [api_lb, pool_id]}

  ######################################################################
  #
  # Mesos slaves. This is a resource group that will initially
  # create <number_of_slaves> slaves, and needs to be manually scaled.
  #

  mesos_slaves:
    type: OS::Heat::ResourceGroup
    depends_on:
      - network
    properties:
      count: {get_param: number_of_slaves}
      removal_policies: [{resource_list: {get_param: slaves_to_remove}}]
      resource_def:
        type: mesosslave.yaml
        properties:
          ssh_key_name: {get_param: ssh_key_name}
          server_image: {get_param: server_image}
          slave_flavor: {get_param: slave_flavor}
          fixed_network: {get_attr: [network, fixed_network]}
          fixed_subnet: {get_attr: [network, fixed_subnet]}
          external_network: {get_param: external_network}
          secgroup_slave_all_open_id: {get_resource: secgroup_slave_all_open}
          mesos_slave_software_configs: {get_attr: [mesos_slave_software_configs, mesos_init]}

  ######################################################################
  #
  # Wait condition handler for Mesos slaves.
  #

  slave_wait_handle:
    type: OS::Heat::WaitConditionHandle

  slave_wait_condition:
    type: OS::Heat::WaitCondition
    properties:
      count: {get_param: number_of_slaves}
      handle: {get_resource: slave_wait_handle}
      timeout: {get_param: wait_condition_timeout}

  ######################################################################
  #
  # Software configs for Mesos slaves.
  #

  mesos_slave_software_configs:
    type: mesos_slave_software_configs.yaml
    properties:
      mesos_masters_ips: {list_join: [' ', {get_attr: [mesos_masters, mesos_master_ip]}]}
      executor_registration_timeout: {get_param: executor_registration_timeout}
      http_proxy: {get_param: http_proxy}
      https_proxy: {get_param: https_proxy}
      no_proxy: {get_param: no_proxy}
      auth_url: {get_param: auth_url}
      username: {get_param: username}
      password: {get_param: password}
      tenant_name: {get_param: tenant_name}
      volume_driver: {get_param: volume_driver}
      region_name: {get_param: region_name}
      domain_name: {get_param: domain_name}
      rexray_preempt: {get_param: rexray_preempt}
      mesos_slave_isolation: {get_param: mesos_slave_isolation}
      mesos_slave_work_dir: {get_param: mesos_slave_work_dir}
      mesos_slave_image_providers: {get_param: mesos_slave_image_providers}
      mesos_slave_executor_env_variables: {get_param: mesos_slave_executor_env_variables}
      mesos_slave_wc_curl_cli: {get_attr: [slave_wait_handle, curl_cli]}

outputs:

  api_address:
    value: {get_attr: [api_address_lb_switch, public_ip]}
    description: >
      This is the API endpoint of the Mesos master. Use this to access
      the Mesos API from outside the cluster.

  mesos_master_private:
    value: {get_attr: [mesos_masters, mesos_master_ip]}
    description: >
      This is a list of the "private" addresses of all the Mesos masters.

  mesos_master:
    value: {get_attr: [mesos_masters, mesos_master_external_ip]}
    description: >
      This is the "public" ip address of the Mesos master server.  Use this address to
      log in to the Mesos master via ssh or to access the Mesos API
      from outside the cluster.

  mesos_slaves_private:
    value: {get_attr: [mesos_slaves, mesos_slave_ip]}
    description: >
      This is a list of the "private" addresses of all the Mesos slaves.

  mesos_slaves:
    value: {get_attr: [mesos_slaves, mesos_slave_external_ip]}
    description: >
      This is a list of the "public" addresses of all the Mesos slaves.
