# Setup a machine with Tempest to do testing of the cluster
class oci::tempest(
  $region_name              = 'RegionOne',
  $openstack_release        = undef,
  $cluster_name             = undef,
  $machine_hostname         = undef,
  $machine_ip               = undef,

  $vip_hostname             = undef,
  $self_signed_api_cert     = true,

  $cluster_has_cinder       = false,
  $cluster_has_ceph         = false,
  $cluster_has_compute      = false,
  $cluster_has_swift        = false,

  $pass_keystone_adminuser  = undef,

  $glance_image_path        = undef,
  $glance_image_name        = undef,
  $glance_image_user        = 'debian',

  $neutron_external_network_name = 'ext-net1',
  $neutron_floating_network_name = 'ext-floating1',
  $nova_flavor_name         = 'demo-flavor',

  $refstack_no_object_test_list = undef,
  $refstack_object_test_list    = undef,

  $pass_root_rally_db       = undef,
  $pass_rally_db            = undef,

  # From variables.json
  $kernel_from_backports    = false,

  $external_keystone_activate              = false,
  $external_keystone_url                   = 'https://api.example.com/identity',
  $external_keystone_admin_password        = undef,
  $external_keystone_region_prefixed_users = false,
){

  $proto = 'https'
  $messaging_default_port = '5671'
  $messaging_notify_port = '5671'
  $api_port = 443

  $base_url = "${proto}://${vip_hostname}"
  if $self_signed_api_cert {
    $api_endpoint_ca_file = "/etc/ssl/certs/oci-pki-oci-ca-chain.pem"
  }else{
    $api_endpoint_ca_file = ''
  }
  $oci_pki_root_ca_file = '/etc/ssl/certs/oci-pki-oci-ca-chain.pem'

  class { '::oci::puppet_oci_ca_cert':
    self_signed_api_cert => $self_signed_api_cert,
  }

  $keystone_auth_uri  = "${base_url}:${api_port}/identity"
  $keystone_admin_uri = "${base_url}:${api_port}/identity"

  ensure_resource('file', '/root/oci-openrc', {
    'ensure'  => 'present',
    'content' => "
export OS_AUTH_TYPE=password
export OS_PROJECT_DOMAIN_NAME='default'
export OS_USER_DOMAIN_NAME='default'
export OS_PROJECT_NAME='admin'
export OS_USERNAME='admin'
export OS_PASSWORD='${pass_keystone_adminuser}'
export OS_AUTH_URL='${base_url}/identity/v3'
export OS_IDENTITY_API_VERSION=3
export OS_IMAGE_API_VERSION=2
export OS_CACERT=${$api_endpoint_ca_file}
",
    'mode'    => '0640',
  })

  case $openstack_release {
    'rocky':    {
      $max_nova_microversion = '2.65'
      $max_plac_microversion = '1.30'
    }
    'stein':    {
      $max_nova_microversion = '2.72'
      $max_plac_microversion = '1.31'
    }
    'train':    {
      $max_nova_microversion = '2.79'
      $max_plac_microversion = '1.36'
    }
    'ussuri':   {
      $max_nova_microversion = '2.87'
      $max_plac_microversion = '1.36'
    }
    'victoria': {
      $max_nova_microversion = '2.87'
      $max_plac_microversion = '1.36'
    }
    'wallaby':  {
      $max_nova_microversion = '2.88'
      $max_plac_microversion = '1.36'
    }
    'xena':     {
      $max_nova_microversion = '2.90'
      $max_plac_microversion = '1.38'
    }
    'yoga':     {
      $max_nova_microversion = '2.90'
      $max_plac_microversion = '1.39'
    }
    'zed':	{
      $max_nova_microversion = '2.91'
      $max_plac_microversion = '1.39'
    }
    'antelope':	{
      $max_nova_microversion = '2.94'
      $max_plac_microversion = '1.39'
    }
    'bobcat':	{
      $max_nova_microversion = '2.95'
      $max_plac_microversion = '1.39'
    }
    default:    {
      $max_nova_microversion = '2.90'
      $max_plac_microversion = '1.38'
    }
  }

  class { '::tempest':
    package_ensure                   => 'present',
    tempest_workspace                => '/var/lib/tempest',
    install_from_source              => false,
    git_clone                        => false,
    tempest_config_file              => '/etc/tempest/tempest.conf',
    setup_venv                       => false,
    use_dynamic_credentials	     => false,

    # Glance image config
    #
    configure_images                 => true,
    image_name                       => $glance_image_name,
    image_name_alt                   => $glance_image_name,
    glance_v1                        => false,
    glance_v2                        => true,

    # Neutron network config
    #
    configure_networks               => true,
    public_network_name              => $neutron_external_network_name,
    neutron_api_extensions           => [
      'address-group',
      'address-scope',
      'agent',
      'agent-resources-synced',
      'allowed-address-pairs',
      'auto-allocated-topology',
      'availability_zone',
      'availability_zone_filter',
      'bgp',
      'bgp_4byte_asn',
      'bgp_dragent_scheduler',
      'binding',
      'binding-extended',
      'default-subnetpools',
      'dhcp_agent_scheduler',
      'dvr',
      'empty-string-filtering',
      'external-net',
      'ext-gw-mode',
      'extra_dhcp_opt',
      'extraroute',
      'extraroute-atomic',
      'fip-port-details',
      'flavors',
      'floatingip-pools',
      'ip_allocation',
      'ip-substring-filtering',
      'l2_adjacency',
      'l3_agent_scheduler',
      'l3-flavors',
      'l3-ha',
      'l3-port-ip-change-not-allowed',
      'metering',
      'metering_source_and_destination_fields',
      'multi-provider',
      'net-mtu',
      'net-mtu-writable',
      'network_availability_zone',
      'network-ip-availability',
      'pagination',
      'port-mac-address-regenerate',
      'port-resource-request',
      'port-security',
      'port-security-groups-filtering',
      'project-id',
      'provider',
      'qos',
      'qos-bw-limit-direction',
      'qos-bw-minimum-ingress',
      'qos-default',
      'qos-fip',
      'qos-gateway-ip',
      'qos-port-network-policy',
      'qos-rule-type-details',
      'quota_details',
      'quotas',
      'rbac-address-scope',
      'rbac-policies',
      'rbac-security-groups',
      'rbac-subnetpool',
      'revision-if-match',
      'router',
      'router-admin-state-down-before-update',
      'router_availability_zone',
      'security-group',
      'segment',
      'segments-peer-subnet-host-routes',
      'service-type',
      'sorting',
      'standard-attr-description',
      'standard-attr-revisions',
      'standard-attr-segment',
      'standard-attr-tag',
      'standard-attr-timestamp',
      'stateful-security-group',
      'subnet_allocation',
      'subnet_onboard',
      'subnetpool-prefix-ops',
      'subnet-segmentid-writable',
      'subnet-service-types',
      'trunk',
      'trunk-details',
    ],

    # Horizon dashboard config
    login_url                        => "${base_url}/horizon",
    dashboard_url                    => "${base_url}/horizon",
    disable_dashboard_ssl_validation => true,

    # tempest.conf parameters
    #
    identity_uri_v3                  => "${keystone_auth_uri}/v3",
    cli_dir                          => '/usr/bin',
    lock_path                        => '/var/lib/tempest',
    log_file                         => '/var/lib/tempest/tempest-log.log',
    debug                            => true,
    use_stderr                       => true,
    use_syslog                       => false,
    logging_context_format_string    => $::os_service_default,
    attach_encrypted_volume          => false,

    # admin user
    admin_username                   => 'admin',
    admin_password                   => $pass_keystone_adminuser,
    admin_project_name               => 'admin',
    admin_role                       => 'admin',
    admin_domain_name                => 'Default',

    # roles fo the users created by tempest
    tempest_roles                    => ['member', 'creator', 'SwiftOperator', 'heat_stack_user', 'load-balancer_member'],

    # image information
    image_ssh_user                   => $glance_image_user,
    image_alt_ssh_user               => $glance_image_user,
    flavor_name                      => $nova_flavor_name,
    flavor_name_alt                  => $nova_flavor_name,
    compute_build_interval           => 10,
    run_ssh                          => true,

    # testing features that are supported
    resize_available                 => false,
    change_password_available        => false,

    # Service configuration
    cinder_available                 => $cluster_has_cinder,
    cinder_backup_available          => false,
    glance_available                 => true,
    heat_available                   => true,
    ceilometer_available             => $cluster_has_ceph,
    aodh_available                   => $cluster_has_ceph,
    gnocchi_available                => $cluster_has_ceph,
    designate_available              => false,
    horizon_available                => true,
    neutron_available                => true,
    neutron_bgpvpn_available         => false,
    neutron_l2gw_available           => false,
    neutron_vpnaas_available         => false,
    neutron_dr_available             => false,
    nova_available                   => $cluster_has_compute,
    murano_available                 => false,
    sahara_available                 => false,
    swift_available                  => $cluster_has_swift,
    trove_available                  => false,
    ironic_available                 => false,
    watcher_available                => false,
    zaqar_available                  => false,
    ec2api_available                 => false,
    mistral_available                => false,
    vitrage_available                => false,
    octavia_available                => $cluster_has_compute,
    barbican_available               => true,
    keystone_v2                      => false,
    keystone_v3                      => true,
    auth_version                     => 'v3',
    run_service_broker_tests         => false,
    ca_certificates_file             => $api_endpoint_ca_file,
    disable_ssl_validation           => true,
    manage_tests_packages            => true,
    # scenario options
    img_file                         => 'cirros-0.4.0-x86_64-disk.img',

    # The default timout of 30 seconds can sometimes make some functional test fail
    # with big OS image. For example, this one failed with the Ubuntu image:
    # tempest.api.compute.servers.test_create_server.ServersTestManualDisk.test_host_name_is_same_as_server_name
    # tempest.api.compute.images.test_images_oneserver.ImagesOneServerTestJSON.test_create_image_specify_multibyte_character_image_name
    ssh_timeout                      => 120,
    # Same problem with images, which we upload to swift, which is kind of slow
    # tempest.api.compute.images.test_images_oneserver.ImagesOneServerTestJSON.test_create_delete_image
    # tempest.api.compute.images.test_images_oneserver.ImagesOneServerTestJSON.test_create_image_specify_multibyte_character_image_name
    image_build_timeout              => 600,
    compute_max_microversion         => $max_nova_microversion,
    placement_max_microversion       => $max_plac_microversion,
  }

#  tempest_config {
#    'compute-feature-enabled/block_migration_for_live_migration': value => true;
#  }
  Tempest_config {
    path => '/etc/tempest/tempest.conf',
  }
  tempest_config {
    'auth/test_accounts_file':                          value => '/etc/tempest/accounts.yaml';
    'auth/create_isolated_networks':                    value => true;
    'compute/build_timeout':                            value => '600';
    'compute/ready_wait':                               value => '60';
    'compute/fixed_network_name':                       value => $neutron_external_network_name;
    'compute-feature-enabled/vnc_console':              value => true;
    'compute-feature-enabled/rescue':                   value => true;
    'compute-feature-enabled/snapshot':                 value => true;
    'compute-feature-enabled/xenapi_apis':              value => true;
    'compute-feature-enabled/ide_bus':                  value => true;
    'identity/admin_domain_scope':                      value => true;
    'identity-feature-enabled/security_compliance':     value => true;
    'identity-feature-enabled/application_credentials': value => true;
    'image-feature-enabled/import_image':               value => true;
    'network/floating_network_name':                    value => $neutron_floating_network_name;
    'network-feature-enabled/ipv6':                     value => false;
    'network-feature-enabled/available_features':       value => 'all';
    'network-feature-enabled/ipv6_subnet_attributes':   value => true;
    'network-feature-enabled/port_admin_state_change':  value => true;
    'volume/build_timeout':                             value => '600';
    'volume/volume_size':                               value => '2';
    'volume-feature-enabled/manage_volume':             value => true;
    'volume-feature-enabled/api_extensions':            value => 'all';
  }

  # Setup the refstack client
  package { 'refstack-client':
    ensure  => 'present',
    tag     => ['openstack', ],
    require => Class['::tempest'],
  }->
  exec { 'create-account.yaml':
    command => "/usr/bin/tempest account-generator --os-username admin --os-password ${pass_keystone_adminuser} --os-project-name admin --concurrency 3 /etc/tempest/accounts.yaml",
    creates => '/etc/tempest/accounts.yaml',
    timeout => 600,
  }->
  file { '/etc/tempest/platform.2021.11-test-list.txt':
    owner   => 'root',
    group   => 'root',
    mode    => '0644',
    content => base64('decode', $refstack_no_object_test_list),
  }->
  file { '/etc/tempest/platform-object.2021.11-test-list.txt':
    owner   => 'root',
    group   => 'root',
    mode    => '0644',
    content => base64('decode', $refstack_object_test_list),
  }

  $ram_total_in_mb = Integer($facts['memorysize_mb'])
  $ram_total_in_gb = $ram_total_in_mb / 1024
  $ram_total_in_gb_div_4 = $ram_total_in_gb / 4

  if $ram_total_in_gb_div_4 > 64 {
    $innodb_buffer_pool_size = 64
  }elsif $ram_total_in_gb_div_4 > 32{
    $innodb_buffer_pool_size = 32
  }elsif $ram_total_in_gb_div_4 > 16{
    $innodb_buffer_pool_size = 16
  }elsif $ram_total_in_gb_div_4 > 8{
    $innodb_buffer_pool_size = 8
  }elsif $ram_total_in_gb_div_4 > 4{
    $innodb_buffer_pool_size = 4
  }else{
    $innodb_buffer_pool_size = 2
  }

  class { '::mysql::client':
    package_name   => 'default-mysql-client',
  }
  -> class { '::mysql::server':
    package_name          => 'mariadb-server',
    root_password         => $pass_root_rally_db,
    override_options => {
      'mysqld' => {
        'bind_address'                    => $machine_ip,
        'wait_timeout'                    => '28800',
        'interactive_timeout'             => '30',
        'connect_timeout'                 => '30',
        'character_set_server'            => 'utf8',
        'collation_server'                => 'utf8_general_ci',
        'innodb_buffer_pool_size'         => "${innodb_buffer_pool_size}G",
        'innodb_flush_log_at_trx_commit'  => '2',
        'max_connections'                 => '5000',
        'max_user_connections'            => '1000',
        'binlog_cache_size'               => '1M',
        'log-bin'                         => 'mysql-bin',
        'binlog_format'                   => 'ROW',
        'performance_schema'              => '1',
        'log_warnings'                    => '2',
        'wsrep_sst_auth'                  => "backup:${pass_root_rally_db}",
        'wsrep_sst_method'                => 'mariabackup',
        'wsrep_cluster_name'              => $machine_hostname,
        'wsrep_node_name'                 => $machine_hostname,
        'wsrep_provider_options'          => 'cert.log_conflicts=YES;gcache.recover=yes;gcache.size=5G',
      }
    }
  }

  class { '::rally::db::mysql':
    dbname        => 'rallydb',
    user          => 'rally',
    password      => $pass_rally_db,
    allowed_hosts => '%',
    charset       => 'utf8mb3',
    collate       => 'utf8mb3_general_ci',
    require       => Anchor['mysql::server::end'],
    before        => Anchor['rally::service::begin'],
  }

  class { '::rally::db':
    database_connection              => "mysql+pymysql://rally:${pass_rally_db}@${machine_ip}/rallydb?charset=utf8",
    database_connection_recycle_time => 1800,
  }
  class { '::rally':
    sync_db => false,
  }
  class { '::rally::db::sync':
    upgrade => true,
  }
}
