aboutsummaryrefslogtreecommitdiffstats
path: root/puppet
diff options
context:
space:
mode:
authorPradeep Kilambi <pkilambi@redhat.com>2016-03-11 19:24:41 -0500
committerPradeep Kilambi <pkilambi@redhat.com>2016-04-11 12:27:38 -0400
commit0970068cbb49d7c4dde6eb2e324058f9b4652c6d (patch)
treee97619b10a361d7872aee8abc23db8f1ec610cb2 /puppet
parent2d4c27dac5efc33cdd547ad2bcdd88f28809052b (diff)
Deploy Gnocchi as a Ceilometer metrics storage backend
* Deploy Gnocchi API. * Storage backends: swift, rbd and file. * Indexer backend default to mysql * Configure Ceilometer to send metrics datas to Gnocchi * Pacemaker config Depends-On: Ic8778a3104e0ed0460423e4bf857682220dc5802 Depends-On: I7d2eb9405e0171fc54fa0b616122f69db5f51ce2 Co-Authored-By: Pradeep Kilambi <pkilambi@redhat.com> Change-Id: Ifde17b1ab8fa2b30544633e455e1c7eb475705aa
Diffstat (limited to 'puppet')
-rw-r--r--puppet/all-nodes-config.yaml10
-rw-r--r--puppet/ceph-cluster-config.yaml14
-rw-r--r--puppet/controller.yaml59
-rw-r--r--puppet/extraconfig/ceph/ceph-external-config.yaml14
-rw-r--r--puppet/hieradata/common.yaml3
-rw-r--r--puppet/hieradata/controller.yaml16
-rw-r--r--puppet/hieradata/database.yaml8
-rw-r--r--puppet/manifests/overcloud_controller.pp24
-rw-r--r--puppet/manifests/overcloud_controller_pacemaker.pp65
-rw-r--r--puppet/vip-config.yaml1
10 files changed, 212 insertions, 2 deletions
diff --git a/puppet/all-nodes-config.yaml b/puppet/all-nodes-config.yaml
index fed9dd31..90eb1b09 100644
--- a/puppet/all-nodes-config.yaml
+++ b/puppet/all-nodes-config.yaml
@@ -44,6 +44,8 @@ parameters:
type: comma_delimited_list
glance_registry_node_ips:
type: comma_delimited_list
+ gnocchi_api_node_ips:
+ type: comma_delimited_list
cinder_api_node_ips:
type: comma_delimited_list
neutron_api_node_ips:
@@ -197,6 +199,14 @@ resources:
list_join:
- "','"
- {get_param: aodh_api_node_ips}
+ gnocchi_api_node_ips:
+ str_replace:
+ template: "['SERVERS_LIST']"
+ params:
+ SERVERS_LIST:
+ list_join:
+ - "','"
+ - {get_param: gnocchi_api_node_ips}
nova_api_node_ips:
str_replace:
template: "['SERVERS_LIST']"
diff --git a/puppet/ceph-cluster-config.yaml b/puppet/ceph-cluster-config.yaml
index dc2f98ed..6c6be473 100644
--- a/puppet/ceph-cluster-config.yaml
+++ b/puppet/ceph-cluster-config.yaml
@@ -36,6 +36,9 @@ parameters:
GlanceRbdPoolName:
default: images
type: string
+ GnocchiRbdPoolName:
+ default: metrics
+ type: string
CephClientUserName:
default: openstack
type: string
@@ -94,7 +97,7 @@ resources:
secret: 'ADMIN_KEY',
mode: '0644',
cap_mon: 'allow r',
- cap_osd: 'allow class-read object_prefix rbd_children, allow rwx pool=CINDER_POOL, allow rwx pool=NOVA_POOL, allow rwx pool=GLANCE_POOL'
+ cap_osd: 'allow class-read object_prefix rbd_children, allow rwx pool=CINDER_POOL, allow rwx pool=NOVA_POOL, allow rwx pool=GLANCE_POOL, allow rwx pool=GNOCCHI_POOL'
}
}"
params:
@@ -103,9 +106,12 @@ resources:
NOVA_POOL: {get_param: NovaRbdPoolName}
CINDER_POOL: {get_param: CinderRbdPoolName}
GLANCE_POOL: {get_param: GlanceRbdPoolName}
+ GNOCCHI_POOL: {get_param: GnocchiRbdPoolName}
nova::compute::rbd::libvirt_images_rbd_pool: {get_param: NovaRbdPoolName}
cinder_rbd_pool_name: {get_param: CinderRbdPoolName}
glance::backend::rbd::rbd_store_pool: {get_param: GlanceRbdPoolName}
+ gnocchi::storage::ceph::ceph_pool: {get_param: GnocchiRbdPoolName}
+ gnocchi::storage::ceph::ceph_username: {get_param: CephClientUserName}
nova::compute::rbd::libvirt_rbd_user: {get_param: CephClientUserName}
glance::backend::rbd::rbd_store_user: {get_param: CephClientUserName}
nova::compute::rbd::rbd_keyring:
@@ -113,11 +119,17 @@ resources:
- '.'
- - 'client'
- {get_param: CephClientUserName}
+ gnocchi::storage::ceph::ceph_keyring:
+ list_join:
+ - '.'
+ - - 'client'
+ - {get_param: CephClientUserName}
ceph_client_user_name: {get_param: CephClientUserName}
ceph_pools:
- {get_param: CinderRbdPoolName}
- {get_param: NovaRbdPoolName}
- {get_param: GlanceRbdPoolName}
+ - {get_param: GnocchiRbdPoolName}
outputs:
config_id:
diff --git a/puppet/controller.yaml b/puppet/controller.yaml
index dca561fc..56eb8b96 100644
--- a/puppet/controller.yaml
+++ b/puppet/controller.yaml
@@ -34,6 +34,12 @@ parameters:
default: false
description: Whether to store events in ceilometer.
type: boolean
+ CeilometerMeterDispatcher:
+ default: 'database'
+ description: Dispatcher to process meter data
+ type: string
+ constraints:
+ - allowed_values: ['gnocchi', 'database']
CinderApiVirtualIP:
type: string
default: ''
@@ -223,6 +229,24 @@ parameters:
Mount options for Pacemaker mount used as Glance storage.
Effective when GlanceFilePcmkManage is true.
type: string
+ GnocchiBackend:
+ default: file
+ description: The short name of the Gnocchi backend to use. Should be one
+ of swift, rbd, or file
+ type: string
+ constraints:
+ - allowed_values: ['swift', 'file', 'rbd']
+ GnocchiIndexerBackend:
+ default: 'mysql'
+ description: The short name of the Gnocchi indexer backend to use.
+ type: string
+ GnocchiApiVirtualIP:
+ type: string
+ default: ''
+ GnocchiPassword:
+ description: The password for the gnocchi service and db account.
+ type: string
+ hidden: true
HAProxyStatsPassword:
description: Password for HAProxy stats endpoint
type: string
@@ -1098,6 +1122,10 @@ resources:
ceilometer_password: {get_param: CeilometerPassword}
ceilometer_store_events: {get_param: CeilometerStoreEvents}
aodh_password: {get_param: AodhPassword}
+ ceilometer_meter_dispatcher: {get_param: CeilometerMeterDispatcher}
+ gnocchi_password: {get_param: GnocchiPassword}
+ gnocchi_backend: {get_param: GnocchiBackend}
+ gnocchi_indexer_backend: {get_param: GnocchiIndexerBackend}
ceilometer_coordination_url:
list_join:
- ''
@@ -1114,6 +1142,15 @@ resources:
- '@'
- {get_param: MysqlVirtualIPUri}
- '/ceilometer'
+ gnocchi_dsn:
+ list_join:
+ - ''
+ - - 'mysql+pymysql://gnocchi:'
+ - {get_param: GnocchiPassword}
+ - '@'
+ - {get_param: MysqlVirtualIPUri}
+ - '/gnocchi'
+ gnocchi_internal_url: {get_param: [EndpointMap, GnocchiInternal, uri]}
snmpd_readonly_user_name: {get_param: SnmpdReadonlyUserName}
snmpd_readonly_user_password: {get_param: SnmpdReadonlyUserPassword}
nova_enable_db_purge: {get_param: NovaEnableDBPurge}
@@ -1193,6 +1230,7 @@ resources:
neutron_local_ip: {get_attr: [NetIpMap, net_ip_map, {get_param: [ServiceNetMap, NeutronTenantNetwork]}]}
ceilometer_api_network: {get_attr: [NetIpMap, net_ip_map, {get_param: [ServiceNetMap, CeilometerApiNetwork]}]}
aodh_api_network: {get_attr: [NetIpMap, net_ip_map, {get_param: [ServiceNetMap, AodhApiNetwork]}]}
+ gnocchi_api_network: {get_attr: [NetIpMap, net_ip_map, {get_param: [ServiceNetMap, GnocchiApiNetwork]}]}
nova_api_network: {get_attr: [NetIpMap, net_ip_map, {get_param: [ServiceNetMap, NovaApiNetwork]}]}
nova_metadata_network: {get_attr: [NetIpMap, net_ip_map, {get_param: [ServiceNetMap, NovaMetadataNetwork]}]}
horizon_network: {get_attr: [NetIpMap, net_ip_map, {get_param: [ServiceNetMap, HorizonNetwork]}]}
@@ -1471,6 +1509,11 @@ resources:
ceilometer::agent::central::coordination_url: {get_input: ceilometer_coordination_url}
ceilometer::agent::notification::store_events: {get_input: ceilometer_store_events}
ceilometer::db::mysql::password: {get_input: ceilometer_password}
+ ceilometer::collector::meter_dispatcher: {get_input: ceilometer_meter_dispatcher}
+ ceilometer::dispatcher::gnocchi::url: {get_input: gnocchi_internal_url }
+ ceilometer::dispatcher::gnocchi::filter_project: 'service'
+ ceilometer::dispatcher::gnocchi::archive_policy: 'low'
+ ceilometer::dispatcher::gnocchi::resources_definition_file: 'gnocchi_resources.yaml'
snmpd_readonly_user_name: {get_input: snmpd_readonly_user_name}
snmpd_readonly_user_password: {get_input: snmpd_readonly_user_password}
@@ -1492,6 +1535,22 @@ resources:
# for a migration path from ceilometer-alarm to aodh, we use the same database & coordination
aodh::evaluator::coordination_url: {get_input: ceilometer_coordination_url}
+ # Gnocchi
+ gnocchi_backend: {get_input: gnocchi_backend}
+ gnocchi_indexer_backend: {get_input: gnocchi_indexer_backend}
+ gnocchi_mysql_conn_string: {get_input: gnocchi_dsn}
+ gnocchi::debug: {get_input: debug}
+ gnocchi::wsgi::apache::ssl: false
+ gnocchi::wsgi::apache::bind_host: {get_input: gnocchi_api_network}
+ gnocchi::api::service_name: 'httpd'
+ gnocchi::api::host: {get_input: gnocchi_api_network}
+ gnocchi::api::keystone_password: {get_input: gnocchi_password}
+ gnocchi::api::keystone_auth_uri: {get_input: keystone_auth_uri}
+ gnocchi::api::keystone_identity_uri: {get_input: keystone_identity_uri}
+ gnocchi::db::mysql::password: {get_input: gnocchi_password}
+ gnocchi::storage::swift::swift_authurl: {get_input: keystone_auth_uri}
+ gnocchi::storage::swift::swift_key: {get_input: gnocchi_password}
+
# Nova
nova::rabbit_userid: {get_input: rabbit_username}
nova::rabbit_password: {get_input: rabbit_password}
diff --git a/puppet/extraconfig/ceph/ceph-external-config.yaml b/puppet/extraconfig/ceph/ceph-external-config.yaml
index 312d49a0..5942088c 100644
--- a/puppet/extraconfig/ceph/ceph-external-config.yaml
+++ b/puppet/extraconfig/ceph/ceph-external-config.yaml
@@ -38,6 +38,9 @@ parameters:
GlanceRbdPoolName:
default: images
type: string
+ GnocchiRbdPoolName:
+ default: metrics
+ type: string
CephClientUserName:
default: openstack
type: string
@@ -68,7 +71,7 @@ resources:
secret: 'CLIENT_KEY',
mode: '0644',
cap_mon: 'allow r',
- cap_osd: 'allow class-read object_prefix rbd_children, allow rwx pool=CINDER_POOL, allow rwx pool=NOVA_POOL, allow rwx pool=GLANCE_POOL'
+ cap_osd: 'allow class-read object_prefix rbd_children, allow rwx pool=CINDER_POOL, allow rwx pool=NOVA_POOL, allow rwx pool=GLANCE_POOL, allow rwx pool=GNOCCHI_POOL'
}
}"
params:
@@ -77,10 +80,13 @@ resources:
NOVA_POOL: {get_param: NovaRbdPoolName}
CINDER_POOL: {get_param: CinderRbdPoolName}
GLANCE_POOL: {get_param: GlanceRbdPoolName}
+ GNOCCHI_POOL: {get_param: GnocchiRbdPoolName}
ceph::profile::params::ms_bind_ipv6: {get_param: CephIPv6}
nova::compute::rbd::libvirt_images_rbd_pool: {get_param: NovaRbdPoolName}
cinder_rbd_pool_name: {get_param: CinderRbdPoolName}
glance::backend::rbd::rbd_store_pool: {get_param: GlanceRbdPoolName}
+ gnocchi::storage::ceph::ceph_pool: {get_param: GnocchiRbdPoolName}
+ gnocchi::storage::ceph::ceph_username: {get_param: CephClientUserName}
nova::compute::rbd::libvirt_rbd_user: {get_param: CephClientUserName}
glance::backend::rbd::rbd_store_user: {get_param: CephClientUserName}
nova::compute::rbd::rbd_keyring:
@@ -88,11 +94,17 @@ resources:
- '.'
- - 'client'
- {get_param: CephClientUserName}
+ gnocchi::storage::ceph::ceph_keyring:
+ list_join:
+ - '.'
+ - - 'client'
+ - {get_param: CephClientUserName}
ceph_client_user_name: {get_param: CephClientUserName}
ceph_pools:
- {get_param: CinderRbdPoolName}
- {get_param: NovaRbdPoolName}
- {get_param: GlanceRbdPoolName}
+ - {get_param: GnocchiRbdPoolName}
outputs:
config_id:
diff --git a/puppet/hieradata/common.yaml b/puppet/hieradata/common.yaml
index 46471c3b..34965959 100644
--- a/puppet/hieradata/common.yaml
+++ b/puppet/hieradata/common.yaml
@@ -8,6 +8,9 @@ ceilometer::agent::auth::auth_tenant_name: 'service'
aodh::auth::auth_region: 'regionOne'
aodh::auth::auth_tenant_name: 'service'
+gnocchi::auth::auth_region: 'regionOne'
+gnocchi::auth::auth_tenant_name: 'service'
+
nova::api::admin_tenant_name: 'service'
nova::network::neutron::neutron_project_name: 'service'
nova::network::neutron::neutron_username: 'neutron'
diff --git a/puppet/hieradata/controller.yaml b/puppet/hieradata/controller.yaml
index 8766263a..79db9418 100644
--- a/puppet/hieradata/controller.yaml
+++ b/puppet/hieradata/controller.yaml
@@ -6,6 +6,16 @@ nova::consoleauth::enabled: true
nova::vncproxy::enabled: true
nova::scheduler::enabled: true
+# gnocchi
+gnocchi::db::sync::extra_opts: '--skip-storage'
+gnocchi::storage::swift::swift_user: 'service:gnocchi'
+gnocchi::storage::swift::swift_auth_version: 2
+gnocchi::statsd::resource_id: '0a8b55df-f90f-491c-8cb9-7cdecec6fc26'
+gnocchi::statsd::user_id: '27c0d3f8-e7ee-42f0-8317-72237d1c5ae3'
+gnocchi::statsd::project_id: '6c38cd8d-099a-4cb2-aecf-17be688e8616'
+gnocchi::statsd::flush_delay: 10
+gnocchi::statsd::archive_policy_name: 'low'
+
# rabbitmq
rabbitmq::delete_guest_user: false
rabbitmq::wipe_db_on_cookie_change: true
@@ -44,6 +54,7 @@ neutron::agents::dhcp::dhcp_delete_namespaces: True
cinder::api::keystone_tenant: 'service'
swift::proxy::authtoken::admin_tenant_name: 'service'
ceilometer::api::keystone_tenant: 'service'
+gnocchi::api::keystone_tenant: 'service'
heat::keystone_tenant: 'service'
sahara::admin_tenant_name: 'service'
@@ -151,6 +162,7 @@ tripleo::loadbalancer::sahara: true
tripleo::loadbalancer::swift_proxy_server: true
tripleo::loadbalancer::ceilometer: true
tripleo::loadbalancer::aodh: true
+tripleo::loadbalancer::gnocchi: true
tripleo::loadbalancer::heat_api: true
tripleo::loadbalancer::heat_cloudwatch: true
tripleo::loadbalancer::heat_cfn: true
@@ -267,3 +279,7 @@ tripleo::firewall::firewall_rules:
port:
- 8042
- 13042
+ '129 gnocchi-api':
+ port:
+ - 8041
+ - 13041
diff --git a/puppet/hieradata/database.yaml b/puppet/hieradata/database.yaml
index 61714691..4eb199c8 100644
--- a/puppet/hieradata/database.yaml
+++ b/puppet/hieradata/database.yaml
@@ -61,6 +61,14 @@ ceilometer::db::mysql::allowed_hosts:
- '%'
- "%{hiera('mysql_bind_host')}"
+# Gnocchi
+gnocchi::db::mysql::user: gnocchi
+gnocchi::db::mysql::host: "%{hiera('mysql_virtual_ip')}"
+gnocchi::db::mysql::dbname: gnocchi
+gnocchi::db::mysql::allowed_hosts:
+ - '%'
+ - "%{hiera('mysql_bind_host')}"
+
sahara::db::mysql::user: sahara
sahara::db::mysql::host: "%{hiera('mysql_virtual_ip')}"
sahara::db::mysql::dbname: sahara
diff --git a/puppet/manifests/overcloud_controller.pp b/puppet/manifests/overcloud_controller.pp
index 0bf5f886..779e7f21 100644
--- a/puppet/manifests/overcloud_controller.pp
+++ b/puppet/manifests/overcloud_controller.pp
@@ -121,6 +121,9 @@ if hiera('step') >= 2 {
include ::cinder::db::mysql
include ::heat::db::mysql
include ::sahara::db::mysql
+ if downcase(hiera('gnocchi_indexer_backend')) == 'mysql' {
+ include ::gnocchi::db::mysql
+ }
if downcase(hiera('ceilometer_backend')) == 'mysql' {
include ::ceilometer::db::mysql
include ::aodh::db::mysql
@@ -577,6 +580,7 @@ if hiera('step') >= 4 {
include ::ceilometer::expirer
include ::ceilometer::collector
include ::ceilometer::agent::auth
+ include ::ceilometer::dispatcher::gnocchi
class { '::ceilometer::db' :
database_connection => $ceilometer_database_connection,
}
@@ -633,6 +637,26 @@ if hiera('step') >= 4 {
neutron_options => $neutron_options,
}
+ # Gnocchi
+ $gnocchi_database_connection = hiera('gnocchi_mysql_conn_string')
+ class { '::gnocchi':
+ database_connection => $gnocchi_database_connection,
+ }
+ include ::gnocchi::api
+ include ::gnocchi::wsgi::apache
+ include ::gnocchi::client
+ include ::gnocchi::db::sync
+ include ::gnocchi::storage
+ include ::gnocchi::metricd
+ include ::gnocchi::statsd
+ $gnocchi_backend = downcase(hiera('gnocchi_backend', 'swift'))
+ case $gnocchi_backend {
+ 'swift': { include ::gnocchi::storage::swift }
+ 'file': { include ::gnocchi::storage::file }
+ 'rbd': { include ::gnocchi::storage::ceph }
+ default: { fail('Unrecognized gnocchi_backend parameter.') }
+ }
+
$snmpd_user = hiera('snmpd_readonly_user_name')
snmp::snmpv3_user { $snmpd_user:
authtype => 'MD5',
diff --git a/puppet/manifests/overcloud_controller_pacemaker.pp b/puppet/manifests/overcloud_controller_pacemaker.pp
index 4cf04d8b..f5d4cf9c 100644
--- a/puppet/manifests/overcloud_controller_pacemaker.pp
+++ b/puppet/manifests/overcloud_controller_pacemaker.pp
@@ -24,6 +24,7 @@ Service <|
tag == 'cinder-service' or
tag == 'ceilometer-service' or
tag == 'glance-service' or
+ tag == 'gnocchi-service' or
tag == 'heat-service' or
tag == 'keystone-service' or
tag == 'neutron-service' or
@@ -543,6 +544,11 @@ MYSQL_HOST=localhost\n",
}
}
+ if downcase(hiera('gnocchi_indexer_backend')) == 'mysql' {
+ class { '::gnocchi::db::mysql':
+ require => Exec['galera-ready'],
+ }
+ }
class { '::sahara::db::mysql':
require => Exec['galera-ready'],
}
@@ -1057,6 +1063,7 @@ if hiera('step') >= 4 {
sync_db => $sync_db,
}
include ::ceilometer::agent::auth
+ include ::ceilometer::dispatcher::gnocchi
Cron <| title == 'ceilometer-expirer' |> { command => "sleep $((\$(od -A n -t d -N 3 /dev/urandom) % 86400)) && ${::ceilometer::params::expirer_command}" }
@@ -1135,6 +1142,40 @@ if hiera('step') >= 4 {
enabled => false,
}
+ # Gnocchi
+ $gnocchi_database_connection = hiera('gnocchi_mysql_conn_string')
+ include ::gnocchi::client
+ if $sync_db {
+ include ::gnocchi::db::sync
+ }
+ include ::gnocchi::storage
+ $gnocchi_backend = downcase(hiera('gnocchi_backend', 'swift'))
+ case $gnocchi_backend {
+ 'swift': { include ::gnocchi::storage::swift }
+ 'file': { include ::gnocchi::storage::file }
+ 'rbd': { include ::gnocchi::storage::ceph }
+ default: { fail('Unrecognized gnocchi_backend parameter.') }
+ }
+ class { '::gnocchi':
+ database_connection => $gnocchi_database_connection,
+ }
+ class { '::gnocchi::api' :
+ manage_service => false,
+ enabled => false,
+ service_name => 'httpd',
+ }
+ class { '::gnocchi::wsgi::apache' :
+ ssl => false,
+ }
+ class { '::gnocchi::metricd' :
+ manage_service => false,
+ enabled => false,
+ }
+ class { '::gnocchi::statsd' :
+ manage_service => false,
+ enabled => false,
+ }
+
$snmpd_user = hiera('snmpd_readonly_user_name')
snmp::snmpv3_user { $snmpd_user:
authtype => 'MD5',
@@ -1781,6 +1822,30 @@ if hiera('step') >= 5 {
}
}
+ # gnocchi
+ pacemaker::resource::service { $::gnocchi::params::metricd_service_name :
+ clone_params => 'interleave=true',
+ }
+ pacemaker::resource::service { $::gnocchi::params::statsd_service_name :
+ clone_params => 'interleave=true',
+ }
+ pacemaker::constraint::base { 'gnocchi-metricd-then-gnocchi-statsd-constraint':
+ constraint_type => 'order',
+ first_resource => "${::gnocchi::params::metricd_service_name}-clone",
+ second_resource => "${::gnocchi::params::statsd_service_name}-clone",
+ first_action => 'start',
+ second_action => 'start',
+ require => [Pacemaker::Resource::Service[$::gnocchi::params::metricd_service_name],
+ Pacemaker::Resource::Service[$::gnocchi::params::statsd_service_name]],
+ }
+ pacemaker::constraint::colocation { 'gnocchi-statsd-with-metricd-colocation':
+ source => "${::gnocchi::params::statsd_service_name}-clone",
+ target => "${::gnocchi::params::metricd_service_name}-clone",
+ score => 'INFINITY',
+ require => [Pacemaker::Resource::Service[$::gnocchi::params::metricd_service_name],
+ Pacemaker::Resource::Service[$::gnocchi::params::statsd_service_name]],
+ }
+
# Heat
pacemaker::resource::service { $::heat::params::api_service_name :
clone_params => 'interleave=true',
diff --git a/puppet/vip-config.yaml b/puppet/vip-config.yaml
index ebecd0cb..3e8e9182 100644
--- a/puppet/vip-config.yaml
+++ b/puppet/vip-config.yaml
@@ -27,6 +27,7 @@ resources:
nova_metadata_vip: {get_input: nova_metadata_vip}
ceilometer_api_vip: {get_input: ceilometer_api_vip}
aodh_api_vip: {get_input: aodh_api_vip}
+ gnocchi_api_vip: {get_input: gnocchi_api_vip}
heat_api_vip: {get_input: heat_api_vip}
horizon_vip: {get_input: horizon_vip}
redis_vip: {get_input: redis_vip}