Puppet: overcloud controller config
authorDan Prince <dprince@redhat.com>
Sat, 20 Dec 2014 02:48:45 +0000 (21:48 -0500)
committerDan Prince <dprince@redhat.com>
Thu, 8 Jan 2015 14:52:50 +0000 (09:52 -0500)
This patch provides an alternate implementation of
the OS::TripleO::Controller::SoftwareConfig which uses Puppet
to drive the configuration. Using this it is possible
to create a fully functional overcloud controller instance
which has the controller node configured via Puppet
stackforge modules. Initially this includes only the
following services:

  MySQL
  RabbitMQ
  Keepalived/HAProxy (HA is not yet fully supported however)
  Nova
  Neutron
  Keystone
  Glance (file backend)
  Cinder

Using these services it is possible to run devtest_overcloud.sh
to completion. The idea is that we can quickly add more
services once we have CI in place.

In order to test this you'll want to build your images
with these elements:

   os-net-config
   heat-config-puppet
   puppet-modules
   hiera

None of the OpenStack specific TripleO elements
should be used with this approach (the nova/neutron
elements were NOT used to build the controller image).

Also, rather than use neutron-openvswitch-agent to configure
low level networking it is recommended that os-net-config
by configured directly via heat modeling rather than
parameter passing to init-neutron-ovs. This allows us to
configure the physical network while avoiding the coupling to
the neutron-openvswitch-element that our standard
parameter driven networking currently uses. (We still need
to move init-neutron-ovs so that it isn't coupled and/or deprecate
its use entirely because the heat drive stuff is more flexible.)

Packages may optionally be pre-installed via DIB using the
-p option (-p openstack-neutron,openstack-nova) etc.

Change-Id: If8462e4eacb08eced61a8b03fd7c3c4257e0b5b8

controller-config-puppet.yaml [new file with mode: 0644]
overcloud-resource-registry-puppet.yaml
overcloud-resource-registry.yaml
puppet/hieradata/controller.yaml [new file with mode: 0644]
puppet/loadbalancer.pp [new file with mode: 0644]
puppet/overcloud_controller.pp [new file with mode: 0644]

diff --git a/controller-config-puppet.yaml b/controller-config-puppet.yaml
new file mode 100644 (file)
index 0000000..06d991d
--- /dev/null
@@ -0,0 +1,238 @@
+# Copyright 2014 Red Hat, Inc.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+heat_template_version: 2014-10-16
+
+description: >
+  Puppet Software Config for the Controller.
+
+parameters:
+  controller_id:
+    type: string
+    hidden: true
+
+resources:
+
+  # The first manifest we execute is to setup HAProxy/Keepalived.
+  # NOTE(dprince): this example uses a composition class
+  # on the puppet side (loadbalancer.pp). This seemed like the
+  # cleanest way to encapulate the puppet resources definitions
+  # for HAProxy and Keepalived.
+  ControllerLoadbalancerPuppetConfig:
+    type: OS::Heat::SoftwareConfig
+    properties:
+      group: puppet
+      options:
+        enable_hiera: True
+        enable_facter: False
+      inputs:
+      outputs:
+      - name: result
+      config:
+        get_file: puppet/loadbalancer.pp
+
+  ControllerLoadbalancerPuppetDeployment:
+    type: OS::Heat::StructuredDeployment
+    properties:
+      name: puppet_1
+      server: {get_param: controller_id}
+      config: {get_resource: ControllerLoadbalancerPuppetConfig}
+      input_values:
+      signal_transport: NO_SIGNAL
+
+  ControllerPuppetConfig:
+    type: OS::Heat::SoftwareConfig
+    properties:
+      group: puppet
+      options:
+        enable_hiera: True
+        enable_facter: False
+      inputs:
+      - name: step
+      outputs:
+      - name: result
+      config:
+        get_file: puppet/overcloud_controller.pp
+
+  # Step through a series of two more Puppet runs using the same manifest.
+  # NOTE(dprince): Heat breakpoints would make for a really cool way to step
+  # through breakpoints in a controlled manner across the entire cluster
+  ControllerPuppetDeploymentTwo:
+    type: OS::Heat::StructuredDeployment
+    properties:
+      name: puppet_2
+      server: {get_param: controller_id}
+      config: {get_resource: ControllerPuppetConfig}
+      input_values:
+        step: 1
+      signal_transport: NO_SIGNAL
+      actions: ['CREATE'] # no need for two passes on an UPDATE
+
+  ControllerPuppetDeploymentThree:
+    type: OS::Heat::StructuredDeployment
+    properties:
+      name: puppet_3
+      server: {get_param: controller_id}
+      config: {get_resource: ControllerPuppetConfig}
+      input_values:
+        step: 2
+      signal_transport: NO_SIGNAL
+
+  # Map heat metadata into hiera datafiles
+  ControllerConfigImpl:
+    type: OS::Heat::StructuredConfig
+    properties:
+      group: os-apply-config
+      config:
+        hiera:
+          hierarchy:
+            - heat_config_%{::deploy_config_name}
+            - controller
+            - common
+          datafiles:
+            common:
+              raw_data: {get_file: puppet/hieradata/common.yaml}
+            controller:
+              raw_data: {get_file: puppet/hieradata/controller.yaml}
+              oac_data: # data we map in from other OAC configurations
+                bootstrap_nodeid: bootstrap_host.bootstrap_nodeid
+              mapped_data: # data supplied directly to this deployment configuration, etc
+                debug: {get_input: debug}
+                bootstack_nodeid: {get_input: bootstack_nodeid}
+                controller_host: {get_input: controller_host} #local-ipv4
+                # Cinder
+                cinder_lvm_loop_device_size: {get_input: cinder_lvm_loop_device_size}
+                cinder::volume::iscsi::iscsi_helper: {get_input: cinder_iscsi_helper}
+                cinder::volume::iscsi::iscsi_ip_address: {get_input: controller_host}
+                cinder::database_connection: {get_input: cinder_dsn}
+                cinder::api::keystone_password: {get_input: cinder_password}
+                cinder::api::keystone_auth_host: {get_input: controller_virtual_ip}
+                cinder::api::bind_host: {get_input: controller_host}
+                cinder::rabbit_userid: {get_input: rabbit_username}
+                cinder::rabbit_password: {get_input: rabbit_password}
+                #cinder::debug: {get_input: debug}
+                # Glance
+                glance::api::bind_port: {get_input: glance_port}
+                glance::api::bind_host: {get_input: controller_host}
+                glance::api::auth_host: {get_input: controller_virtual_ip}
+                glance::api::registry_host: {get_input: controller_host}
+                glance::api::keystone_password: {get_input: glance_password}
+                # used to construct glance_api_servers
+                glance_port: {get_input: glance_port}
+                glance_protocol: {get_input: glance_protocol}
+                glance_notifier_strategy: {get_input: glance_notifier_strategy}
+                glance_log_file: {get_input: glance_log_file}
+                glance_log_file: {get_input: glance_log_file}
+                glance::api::database_connection: {get_input: glance_dsn}
+                glance::registry::keystone_password: {get_input: glance_password}
+                glance::registry::database_connection: {get_input: glance_dsn}
+                glance::registry::bind_host: {get_input: controller_host}
+                glance::registry::auth_host: {get_input: controller_virtual_ip}
+                # Heat
+                heat_password: {get_input: heat_password}
+                heat_stack_domain_admin_password: {get_input: heat_stack_domain_admin_password}
+                heat_dsn: {get_input: heat_dsn}
+                heat.watch_server_url: {get_input: heat.watch_server_url}
+                heat.metadata_server_url: {get_input: heat.metadata_server_url}
+                heat.waitcondition_server_url: {get_input: heat.waitcondition_server_url}
+                # Keystone
+                keystone::admin_token: {get_input: admin_token}
+                keystone_ca_certificate: {get_input: keystone_ca_certificate}
+                keystone_signing_key: {get_input: keystone_signing_key}
+                keystone_signing_certificate: {get_input: keystone_signing_certificate}
+                keystone_ssl_certificate: {get_input: keystone_ssl_certificate}
+                keystone_ssl_certificate_key: {get_input: keystone_ssl_certificate_key}
+                keystone::database_connection: {get_input: keystone_dsn}
+                keystone::public_bind_host: {get_input: controller_host}
+                keystone::admin_bind_host: {get_input: controller_host}
+                #keystone::debug: {get_input: debug}
+                # MySQL
+                admin_password: {get_input: admin_password}
+                mysql_innodb_buffer_pool_size: {get_input: mysql_innodb_buffer_pool_size}
+                mysql_root_password: {get_input: mysql_root_password}
+                mysql_cluster_name: {get_input: mysql_cluster_name}
+                # Neutron
+                neutron::bind_host: {get_input: controller_host}
+                neutron::rabbit_password: {get_input: rabbit_password}
+                neutron::rabbit_user: {get_input: rabbit_user}
+                #neutron::debug: {get_input: debug}
+                neutron::server::auth_host: {get_input: controller_virtual_ip}
+                neutron::server::database_connection: {get_input: neutron_dsn}
+                neutron::agents::ml2::ovs::enable_tunneling: {get_input: neutron_enable_tunneling}
+                neutron::agents::ml2::ovs::local_ip: {get_input: controller_host}
+                neutron_flat_networks: {get_input: neutron_flat_networks}
+                neutron::agents::metadata::shared_secret: {get_input: neutron_metadata_proxy_shared_secret}
+                neutron_agent_mode: {get_input: neutron_agent_mode}
+                neutron_router_distributed: {get_input: neutron_router_distributed}
+                neutron_mechanism_drivers: {get_input: neutron_mechanism_drivers}
+                neutron_allow_l3agent_failover: {get_input: neutron_allow_l3agent_failover}
+                neutron::plugins::ml2::network_vlan_ranges: {get_input: neutron_network_vlan_ranges}
+                neutron_bridge_mappings: {get_input: neutron_bridge_mappings}
+                neutron_public_interface: {get_input: neutron_public_interface}
+                neutron_public_interface_raw_device: {get_input: neutron_public_interface_raw_device}
+                neutron_public_interface_default_route: {get_input: neutron_public_interface_default_route}
+                neutron_public_interface_tag: {get_input: neutron_public_interface_tag}
+                neutron_tenant_network_type: {get_input: neutron_tenant_network_type}
+                neutron_tunnel_types: {get_input: neutron_tunnel_types}
+                neutron::server::auth_password: {get_input: neutron_password}
+                neutron::agents::metadata::auth_password: {get_input: neutron_password}
+                neutron_dnsmasq_options: {get_input: neutron_dnsmasq_options}
+                neutron_dsn: {get_input: neutron_dsn}
+                # Ceilometer
+                ceilometer_metering_secret: {get_input: ceilometer_metering_secret}
+                ceilometer_password: {get_input: ceilometer_password}
+                ceilometer_dsn: {get_input: ceilometer_dsn}
+                snmpd_readonly_user_name: {get_input: snmpd_readonly_user_name}
+                snmpd_readonly_user_password: {get_input: snmpd_readonly_user_password}
+                # Nova
+                nova::rabbit_userid: {get_input: rabbit_username}
+                nova::rabbit_password: {get_input: rabbit_password}
+                nova::api::auth_host: {get_input: controller_virtual_ip}
+                nova::api::api_bind_address: {get_input: controller_host}
+                nova::api::metadata_listen: {get_input: controller_host}
+                nova::api::admin_password: {get_input: nova_password}
+                nova::database_connection: {get_input: nova_dsn}
+                nova::api::neutron_metadata_proxy_shared_secret: {get_input: neutron_metadata_proxy_shared_secret}
+                # Rabbit
+                rabbit_username: {get_input: rabbit_username}
+                rabbit_password: {get_input: rabbit_password}
+                rabbit_cookie: {get_input: rabbit_cookie}
+                rabbit_client_use_ssl: {get_input: rabbit_client_use_ssl}
+                rabbit_client_port: {get_input: rabbit_client_port}
+                # Misc
+                neutron_public_interface_ip: {get_input: neutron_public_interface_ip}
+                ntp_server: {get_input: ntp_server}
+                control_virtual_interface: {get_input: control_virtual_interface}
+                controller_virtual_ip: {get_input: controller_virtual_ip}
+                public_virtual_interface: {get_input: public_virtual_interface}
+                public_virtual_ip: {get_input: public_virtual_ip}
+                # Load Balancer (composition class parameters)
+                tripleo::loadbalancer::keystone_admin: true
+                tripleo::loadbalancer::keystone_public: true
+                tripleo::loadbalancer::neutron: true
+                tripleo::loadbalancer::cinder: true
+                tripleo::loadbalancer::glance_api: true
+                tripleo::loadbalancer::glance_registry: true
+                tripleo::loadbalancer::nova_ec2: true
+                tripleo::loadbalancer::nova_osapi: true
+                tripleo::loadbalancer::nova_metadata: true
+                tripleo::loadbalancer::nova_novncproxy: true
+                tripleo::loadbalancer::mysql: true
+                tripleo::loadbalancer::rabbitmq: true
+
+outputs:
+  config_id:
+    description: The ID of the ControllerConfigImpl resource.
+    value:
+      {get_resource: ControllerConfigImpl}
index 30afa81..56f3aa2 100644 (file)
@@ -4,5 +4,6 @@ resource_registry:
   OS::TripleO::Compute::SoftwareConfig: compute-config-puppet.yaml
   OS::TripleO::SoftwareDeployment: OS::Heat::StructuredDeployment
   OS::TripleO::Controller: controller.yaml
+  OS::TripleO::Controller::SoftwareConfig: controller-config-puppet.yaml
   OS::TripleO::ObjectStorage: swift-storage.yaml
   OS::TripleO::Net::SoftwareConfig: net-config-bridge.yaml
index 09a3363..249dee9 100644 (file)
@@ -3,7 +3,7 @@ resource_registry:
   OS::TripleO::Compute: compute.yaml
   OS::TripleO::Compute::SoftwareConfig: compute-config.yaml
   OS::TripleO::SoftwareDeployment: OS::Heat::StructuredDeployment
-  OS::TripleO::Net::SoftwareConfig: net-config-noop.yaml
   OS::TripleO::Controller: controller.yaml
   OS::TripleO::Controller::SoftwareConfig: controller-config.yaml
   OS::TripleO::ObjectStorage: swift-storage.yaml
+  OS::TripleO::Net::SoftwareConfig: net-config-noop.yaml
diff --git a/puppet/hieradata/controller.yaml b/puppet/hieradata/controller.yaml
new file mode 100644 (file)
index 0000000..874d383
--- /dev/null
@@ -0,0 +1,43 @@
+# Hiera data here applies to all controller nodes
+nova::api::enabled: true
+nova::conductor::enabled: true
+nova::consoleauth::enabled: true
+nova::vncproxy::enabled: true
+nova::scheduler::enabled: true
+
+rabbitmq::delete_guest_user: false
+rabbitmq::wipe_db_on_cookie_change: true
+rabbitmq::port: '5672'
+rabbitmq::package_source: undef
+rabbitmq::repos_ensure: false
+
+# service tenant
+nova::api::admin_tenant_name: 'service'
+glance::api::keystone_tenant: 'service'
+glance::registry::keystone_tenant: 'service'
+neutron::server::auth_tenant: 'service'
+neutron::agents::metadata::auth_tenant: 'service'
+cinder::api::keystone_tenant: 'service'
+
+# glance
+glance::api::pipeline: 'keystone'
+glance::registry::pipeline: 'keystone'
+glance::registry::manage_service: true
+
+# neutron
+neutron::core_plugin: 'ml2'
+neutron::service_plugins:
+  - 'neutron.services.l3_router.l3_router_plugin.L3RouterPlugin'
+neutron::dhcp_agents_per_network: 2
+neutron::plugins::ml2::tunnel_id_ranges:
+  - '1:1000'
+neutron::server::sync_db: true
+
+# nova
+nova::notify_on_state_change: 'vm_and_task_state'
+nova::api::osapi_v3: true
+
+# cinder
+cinder::scheduler::scheduler_driver: cinder.scheduler.filter_scheduler.FilterScheduler
+
+mysql::server::manage_config_file: true
diff --git a/puppet/loadbalancer.pp b/puppet/loadbalancer.pp
new file mode 100644 (file)
index 0000000..ea834c5
--- /dev/null
@@ -0,0 +1,375 @@
+# Copyright 2014 Red Hat, Inc.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class tripleo::loadbalancer (
+  $keystone_admin     = false,
+  $keystone_public    = false,
+  $neutron            = false,
+  $cinder             = false,
+  $glance_api         = false,
+  $glance_registry    = false,
+  $nova_ec2           = false,
+  $nova_osapi         = false,
+  $nova_metadata      = false,
+  $nova_novncproxy    = false,
+  $ceilometer         = false,
+  $swift_proxy_server = false,
+  $heat_api           = false,
+  $heat_cloudwatch    = false,
+  $heat_cfn           = false,
+  $horizon            = false,
+  $mysql              = false,
+  $rabbitmq           = false,
+) {
+
+  case $::osfamily {
+    'RedHat': {
+      $keepalived_name_is_process = false
+      $keepalived_vrrp_script     = 'systemctl status haproxy.service'
+    } # RedHat
+    'Debian': {
+      $keepalived_name_is_process = true
+      $keepalived_vrrp_script     = undef
+    }
+  }
+
+  class { 'keepalived': }
+  keepalived::vrrp_script { 'haproxy':
+    name_is_process => $keepalived_name_is_process,
+    script          => $keepalived_vrrp_script,
+  }
+
+  # KEEPALIVE INSTANCE CONTROL
+  keepalived::instance { '51':
+    interface     => hiera('control_virtual_interface'),
+    virtual_ips   => [join([hiera('controller_virtual_ip'), ' dev ', hiera('control_virtual_interface')])],
+    state         => 'MASTER',
+    track_script  => ['haproxy'],
+    priority      => 101,
+  }
+
+  # KEEPALIVE INSTANCE PUBLIC
+  keepalived::instance { '52':
+    interface     => hiera('public_virtual_interface'),
+    virtual_ips   => [join([hiera('public_virtual_ip'), ' dev ', hiera('public_virtual_interface')])],
+    state         => 'MASTER',
+    track_script  => ['haproxy'],
+    priority      => 101,
+  }
+
+  sysctl::value { 'net.ipv4.ip_nonlocal_bind': value => '1' }
+
+  class { 'haproxy':
+    global_options   => {
+      'log'     => '/dev/log local0',
+      'pidfile' => '/var/run/haproxy.pid',
+      'user'    => 'haproxy',
+      'group'   => 'haproxy',
+      'daemon'  => '',
+      'maxconn' => '4000',
+    },
+    defaults_options => {
+      'mode'    => 'tcp',
+      'log'     => 'global',
+      'retries' => '3',
+      'maxconn' => '150',
+      'option'  => [ 'tcpka', 'tcplog' ],
+      'timeout' => [ 'http-request 10s', 'queue 1m', 'connect 10s', 'client 1m', 'server 1m', 'check 10s' ],
+    },
+  }
+
+  haproxy::listen { 'haproxy.stats':
+    ipaddress        => '*',
+    ports            => '1993',
+    mode             => 'http',
+    options          => {
+      'stats' => 'enable',
+    },
+    collect_exported => false,
+  }
+
+  if $keystone_admin {
+    haproxy::listen { 'keystone_admin':
+      ipaddress        => [hiera('controller_virtual_ip'), hiera('public_virtual_ip')],
+      ports            => 35357,
+      options          => { 'option' => [ 'httpchk GET /' ] },
+      collect_exported => false,
+    }
+    haproxy::balancermember { 'keystone_admin':
+      listening_service => 'keystone_admin',
+      ports             => '35357',
+      ipaddresses       => hiera('controller_host'),
+      options           => ['check', 'inter 2000', 'rise 2', 'fall 5'],
+    }
+  }
+
+  if $keystone_public {
+    haproxy::listen { 'keystone_public':
+      ipaddress        => [hiera('controller_virtual_ip'), hiera('public_virtual_ip')],
+      ports            => 5000,
+      options          => { 'option' => [ 'httpchk GET /' ] },
+      collect_exported => false,
+    }
+    haproxy::balancermember { 'keystone_public':
+      listening_service => 'keystone_public',
+      ports             => '5000',
+      ipaddresses       => hiera('controller_host'),
+      options           => ['check', 'inter 2000', 'rise 2', 'fall 5'],
+    }
+  }
+
+  if $neutron {
+    haproxy::listen { 'neutron':
+      ipaddress        => [hiera('controller_virtual_ip'), hiera('public_virtual_ip')],
+      ports            => 9696,
+      options          => { 'option' => [ 'httpchk GET /' ] },
+      collect_exported => false,
+    }
+    haproxy::balancermember { 'neutron':
+      listening_service => 'neutron',
+      ports             => '9696',
+      ipaddresses       => hiera('controller_host'),
+      options           => ['check', 'inter 2000', 'rise 2', 'fall 5'],
+    }
+  }
+
+  if $cinder {
+    haproxy::listen { 'cinder':
+      ipaddress        => [hiera('controller_virtual_ip'), hiera('public_virtual_ip')],
+      ports            => 8776,
+      options          => { 'option' => [ 'httpchk GET /' ] },
+      collect_exported => false,
+    }
+    haproxy::balancermember { 'cinder':
+      listening_service => 'cinder',
+      ports             => '8776',
+      ipaddresses       => hiera('controller_host'),
+      options           => ['check', 'inter 2000', 'rise 2', 'fall 5'],
+    }
+  }
+
+  if $glance_api {
+    haproxy::listen { 'glance_api':
+      ipaddress        => [hiera('controller_virtual_ip'), hiera('public_virtual_ip')],
+      ports            => 9292,
+      options          => { 'option' => [ 'httpchk GET /' ] },
+      collect_exported => false,
+    }
+    haproxy::balancermember { 'glance_api':
+      listening_service => 'glance_api',
+      ports             => '9292',
+      ipaddresses       => hiera('controller_host'),
+      options           => ['check', 'inter 2000', 'rise 2', 'fall 5'],
+    }
+  }
+
+
+  if $glance_registry {
+    haproxy::listen { 'glance_registry':
+      ipaddress        => [hiera('controller_virtual_ip'), hiera('public_virtual_ip')],
+      ports            => 9191,
+      options          => { 'option' => [ 'httpchk GET /' ] },
+      collect_exported => false,
+    }
+    haproxy::balancermember { 'glance_registry':
+      listening_service => 'glance_registry',
+      ports             => '9191',
+      ipaddresses       => hiera('controller_host'),
+      options           => ['check', 'inter 2000', 'rise 2', 'fall 5'],
+    }
+  }
+
+  if $nova_ec2 {
+    haproxy::listen { 'nova_ec2':
+      ipaddress        => [hiera('controller_virtual_ip'), hiera('public_virtual_ip')],
+      ports            => 8773,
+      options          => { 'option' => [ 'httpchk GET /' ] },
+      collect_exported => false,
+    }
+    haproxy::balancermember { 'nova_ec2':
+      listening_service => 'nova_ec2',
+      ports             => '8773',
+      ipaddresses       => hiera('controller_host'),
+      options           => ['check', 'inter 2000', 'rise 2', 'fall 5'],
+    }
+  }
+
+  if $nova_osapi {
+    haproxy::listen { 'nova_osapi':
+      ipaddress        => [hiera('controller_virtual_ip'), hiera('public_virtual_ip')],
+      ports            => 8774,
+      options          => { 'option' => [ 'httpchk GET /' ] },
+      collect_exported => false,
+    }
+    haproxy::balancermember { 'nova_osapi':
+      listening_service => 'nova_osapi',
+      ports             => '8774',
+      ipaddresses       => hiera('controller_host'),
+      options           => ['check', 'inter 2000', 'rise 2', 'fall 5'],
+    }
+  }
+
+  if $nova_metadata {
+    haproxy::listen { 'nova_metadata':
+      ipaddress        => [hiera('controller_virtual_ip'), hiera('public_virtual_ip')],
+      ports            => 8775,
+      options          => { 'option' => [ 'httpchk GET /' ] },
+      collect_exported => false,
+    }
+    haproxy::balancermember { 'nova_metadata':
+      listening_service => 'nova_metadata',
+      ports             => '8775',
+      ipaddresses       => hiera('controller_host'),
+      options           => ['check', 'inter 2000', 'rise 2', 'fall 5'],
+    }
+  }
+
+  if $nova_novncproxy {
+    haproxy::listen { 'nova_novncproxy':
+      ipaddress        => [hiera('controller_virtual_ip'), hiera('public_virtual_ip')],
+      ports            => 6080,
+      options          => { 'option' => [ 'httpchk GET /' ] },
+      collect_exported => false,
+    }
+    haproxy::balancermember { 'nova_novncproxy':
+      listening_service => 'nova_novncproxy',
+      ports             => '6080',
+      ipaddresses       => hiera('controller_host'),
+      options           => ['check', 'inter 2000', 'rise 2', 'fall 5'],
+    }
+  }
+
+  if $ceilometer {
+    haproxy::listen { 'ceilometer':
+      ipaddress        => [hiera('controller_virtual_ip'), hiera('public_virtual_ip')],
+      ports            => 8777,
+      collect_exported => false,
+    }
+    haproxy::balancermember { 'ceilometer':
+      listening_service => 'ceilometer',
+      ports             => '8777',
+      ipaddresses       => hiera('controller_host'),
+      options           => ['check', 'inter 2000', 'rise 2', 'fall 5'],
+    }
+  }
+
+  if $swift_proxy_server {
+    haproxy::listen { 'swift_proxy_server':
+      ipaddress        => [hiera('controller_virtual_ip'), hiera('public_virtual_ip')],
+      ports            => 8080,
+      options          => { 'option' => [ 'httpchk GET /info' ] },
+      collect_exported => false,
+    }
+    haproxy::balancermember { 'swift_proxy_server':
+      listening_service => 'swift_proxy_server',
+      ports             => '8080',
+      ipaddresses       => hiera('controller_host'),
+      options           => ['check', 'inter 2000', 'rise 2', 'fall 5'],
+    }
+  }
+
+  if $heat_api {
+    haproxy::listen { 'heat_api':
+      ipaddress        => [hiera('controller_virtual_ip'), hiera('public_virtual_ip')],
+      ports            => 8004,
+      options          => { 'option' => [ 'httpchk GET /' ] },
+      collect_exported => false,
+    }
+    haproxy::balancermember { 'heat_api':
+      listening_service => 'heat_api',
+      ports             => '8004',
+      ipaddresses       => hiera('controller_host'),
+      options           => ['check', 'inter 2000', 'rise 2', 'fall 5'],
+    }
+  }
+
+  if $heat_cloudwatch {
+    haproxy::listen { 'heat_cloudwatch':
+      ipaddress        => [hiera('controller_virtual_ip'), hiera('public_virtual_ip')],
+      ports            => 8003,
+      options          => { 'option' => [ 'httpchk GET /' ] },
+      collect_exported => false,
+    }
+    haproxy::balancermember { 'heat_cloudwatch':
+      listening_service => 'heat_cloudwatch',
+      ports             => '8003',
+      ipaddresses       => hiera('controller_host'),
+      options           => ['check', 'inter 2000', 'rise 2', 'fall 5'],
+    }
+  }
+
+  if $heat_cfn {
+    haproxy::listen { 'heat_cfn':
+      ipaddress        => [hiera('controller_virtual_ip'), hiera('public_virtual_ip')],
+      ports            => 8000,
+      options          => { 'option' => [ 'httpchk GET /' ] },
+      collect_exported => false,
+    }
+    haproxy::balancermember { 'heat_cfn':
+      listening_service => 'heat_cfn',
+      ports             => '8000',
+      ipaddresses       => hiera('controller_host'),
+      options           => ['check', 'inter 2000', 'rise 2', 'fall 5'],
+    }
+  }
+
+  if $horizon {
+    haproxy::listen { 'horizon':
+      ipaddress        => [hiera('controller_virtual_ip'), hiera('public_virtual_ip')],
+      ports            => 80,
+      options          => { 'option' => [ 'httpchk GET /' ] },
+      collect_exported => false,
+    }
+    haproxy::balancermember { 'horizon':
+      listening_service => 'horizon',
+      ports             => '80',
+      ipaddresses       => hiera('controller_host'),
+      options           => ['check', 'inter 2000', 'rise 2', 'fall 5'],
+    }
+  }
+
+  if $mysql {
+    haproxy::listen { 'mysql':
+      ipaddress        => [hiera('controller_virtual_ip')],
+      ports            => 3306,
+      options          => { 'timeout' => [ 'client 0', 'server 0' ] },
+      collect_exported => false,
+    }
+    haproxy::balancermember { 'mysql':
+      listening_service => 'mysql',
+      ports             => '3306',
+      ipaddresses       => hiera('controller_host'),
+      options           => ['check', 'inter 2000', 'rise 2', 'fall 5'],
+    }
+  }
+
+  if $rabbitmq {
+    haproxy::listen { 'rabbitmq':
+      ipaddress        => [hiera('controller_virtual_ip'), hiera('public_virtual_ip')],
+      ports            => 5672,
+      options          => { 'timeout' => [ 'client 0', 'server 0' ] },
+      collect_exported => false,
+    }
+    haproxy::balancermember { 'rabbitmq':
+      listening_service => 'rabbitmq',
+      ports             => '5672',
+      ipaddresses       => hiera('controller_host'),
+      options           => ['check', 'inter 2000', 'rise 2', 'fall 5'],
+    }
+  }
+
+}
+
+include ::tripleo::loadbalancer
diff --git a/puppet/overcloud_controller.pp b/puppet/overcloud_controller.pp
new file mode 100644 (file)
index 0000000..4c1306f
--- /dev/null
@@ -0,0 +1,209 @@
+# Copyright 2014 Red Hat, Inc.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+if hiera('step') >= 1 {
+
+  # TODO Galara
+  class { 'mysql::server':
+    override_options => {
+      'mysqld' => {
+        'bind-address' => hiera('controller_host')
+      }
+    }
+  }
+
+  # FIXME: this should only occur on the bootstrap host (ditto for db syncs)
+  # Create all the database schemas
+  # Example DSN format: mysql://user:password@host/dbname
+  $allowed_hosts = ['%',hiera('controller_host')]
+  $keystone_dsn = split(hiera('keystone::database_connection'), '[@:/?]')
+  class { 'keystone::db::mysql':
+    user          => $keystone_dsn[3],
+    password      => $keystone_dsn[4],
+    host          => $keystone_dsn[5],
+    dbname        => $keystone_dsn[6],
+    allowed_hosts => $allowed_hosts,
+  }
+  $glance_dsn = split(hiera('glance::api::database_connection'), '[@:/?]')
+  class { 'glance::db::mysql':
+    user          => $glance_dsn[3],
+    password      => $glance_dsn[4],
+    host          => $glance_dsn[5],
+    dbname        => $glance_dsn[6],
+    allowed_hosts => $allowed_hosts,
+  }
+  $nova_dsn = split(hiera('nova::database_connection'), '[@:/?]')
+  class { 'nova::db::mysql':
+    user          => $nova_dsn[3],
+    password      => $nova_dsn[4],
+    host          => $nova_dsn[5],
+    dbname        => $nova_dsn[6],
+    allowed_hosts => $allowed_hosts,
+  }
+  $neutron_dsn = split(hiera('neutron::server::database_connection'), '[@:/?]')
+  class { 'neutron::db::mysql':
+    user          => $neutron_dsn[3],
+    password      => $neutron_dsn[4],
+    host          => $neutron_dsn[5],
+    dbname        => $neutron_dsn[6],
+    allowed_hosts => $allowed_hosts,
+  }
+  $cinder_dsn = split(hiera('cinder::database_connection'), '[@:/?]')
+  class { 'cinder::db::mysql':
+    user          => $cinder_dsn[3],
+    password      => $cinder_dsn[4],
+    host          => $cinder_dsn[5],
+    dbname        => $cinder_dsn[6],
+    allowed_hosts => $allowed_hosts,
+  }
+  $heat_dsn = split(hiera('heat_dsn'), '[@:/?]')
+  class { 'heat::db::mysql':
+    user          => $heat_dsn[3],
+    password      => $heat_dsn[4],
+    host          => $heat_dsn[5],
+    dbname        => $heat_dsn[6],
+    allowed_hosts => $allowed_hosts,
+  }
+
+  if $::osfamily == 'RedHat' {
+    $rabbit_provider = 'yum'
+  } else {
+    $rabbit_provider = undef
+  }
+
+  Class['rabbitmq'] -> Rabbitmq_vhost <| |>
+  Class['rabbitmq'] -> Rabbitmq_user <| |>
+  Class['rabbitmq'] -> Rabbitmq_user_permissions <| |>
+
+  # TODO Rabbit HA
+  class { 'rabbitmq':
+    package_provider  => $rabbit_provider,
+    config_cluster    => false,
+    node_ip_address   => hiera('controller_host'),
+  }
+
+  rabbitmq_vhost { '/':
+    provider => 'rabbitmqctl',
+  }
+  rabbitmq_user { ['nova','glance','neutron','cinder','ceilometer','heat']:
+    admin    => true,
+    password => hiera('rabbit_password'),
+    provider => 'rabbitmqctl',
+  }
+
+  rabbitmq_user_permissions {[
+    'nova@/',
+    'glance@/',
+    'neutron@/',
+    'cinder@/',
+    'ceilometer@/',
+    'heat@/',
+  ]:
+    configure_permission => '.*',
+    write_permission     => '.*',
+    read_permission      => '.*',
+    provider             => 'rabbitmqctl',
+  }
+
+} #END STEP 1
+
+if hiera('step') >= 2 {
+
+  include ::keystone
+
+  #TODO: need a cleanup-keystone-tokens.sh solution here
+  keystone_config {
+    'ec2/driver': value => 'keystone.contrib.ec2.backends.sql.Ec2';
+  }
+  file { [ '/etc/keystone/ssl', '/etc/keystone/ssl/certs', '/etc/keystone/ssl/private' ]:
+    ensure  => 'directory',
+    owner   => 'keystone',
+    group   => 'keystone',
+    require => Package['keystone'],
+  }
+  file { '/etc/keystone/ssl/certs/signing_cert.pem':
+    content => hiera('keystone_signing_certificate'),
+    owner   => 'keystone',
+    group   => 'keystone',
+    notify  => Service['keystone'],
+    require => File['/etc/keystone/ssl/certs'],
+  }
+  file { '/etc/keystone/ssl/private/signing_key.pem':
+    content => hiera('keystone_signing_key'),
+    owner   => 'keystone',
+    group   => 'keystone',
+    notify  => Service['keystone'],
+    require => File['/etc/keystone/ssl/private'],
+  }
+  file { '/etc/keystone/ssl/certs/ca.pem':
+    content => hiera('keystone_ca_certificate'),
+    owner   => 'keystone',
+    group   => 'keystone',
+    notify  => Service['keystone'],
+    require => File['/etc/keystone/ssl/certs'],
+  }
+
+  # TODO: swift backend, also notifications, scrubber, etc.
+  include ::glance::api
+  include ::glance::registry
+
+  class { 'nova':
+    rabbit_hosts           => [hiera('controller_virtual_ip')],
+    glance_api_servers     => join([hiera('glance_protocol'), '://', hiera('controller_virtual_ip'), ':', hiera('glance_port')]),
+  }
+
+  include ::nova::api
+  include ::nova::cert
+  include ::nova::conductor
+  include ::nova::consoleauth
+  include ::nova::vncproxy
+  include ::nova::scheduler
+
+  class {'neutron':
+    rabbit_hosts => [hiera('controller_virtual_ip')],
+  }
+
+  include ::neutron::server
+  include ::neutron::agents::dhcp
+  include ::neutron::agents::l3
+
+  class { 'neutron::plugins::ml2':
+    flat_networks        => split(hiera('neutron_flat_networks'), ','),
+    tenant_network_types => [hiera('neutron_tenant_network_type')],
+    type_drivers         => [hiera('neutron_tenant_network_type')],
+  }
+
+  class { 'neutron::agents::ml2::ovs':
+    bridge_mappings  => split(hiera('neutron_bridge_mappings'), ','),
+    tunnel_types     => split(hiera('neutron_tunnel_types'), ','),
+  }
+
+  class { 'neutron::agents::metadata':
+    auth_url => join(['http://', hiera('controller_virtual_ip'), ':35357/v2.0']),
+  }
+
+  class {'cinder':
+    rabbit_hosts => [hiera('controller_virtual_ip')],
+  }
+
+  include ::cinder::api
+  include ::cinder::scheduler
+  include ::cinder::volume
+  include ::cinder::volume::iscsi
+  class {'cinder::setup_test_volume':
+    size => join([hiera('cinder_lvm_loop_device_size'), 'M']),
+  }
+
+} #END STEP 2