
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
from six.moves import configparser
import textwrap
import glob

_SYSCONFDIR = '/etc'
_DROPPIN_BASES = ("/usr/lib/", "/run/", _SYSCONFDIR)


parameters = [
    ('vars', [

        ('core_dump_enable', 'true',
            'Enable core dump.'),

        ('host_mem_reserve', '256',
            'Reserves memory for the host to prevent VMs from using all the '
            'physical pages. The values are in Mbytes.'),

        ('guest_ram_overhead', '65', None),

        ('extra_mem_reserve', '65',
            'Memory reserved for non-vds-administered programs.'),

        ('fake_nics', 'dummy_*,veth_*',
            'Comma-separated list of fnmatch-patterns for dummy hosts nics to '
            'be shown to vdsm.'),

        ('net_persistence', 'unified',
            'Whether to use "ifcfg" or "unified" persistence for networks.'),

        ('net_nmstate_enabled', 'false',
            'Control nmstate network backend provider.'),

        ('ethtool_opts', '',
            'Which special ethtool options should be applied to NICs after '
            'they are taken up, e.g. "lro off" on buggy devices. '
            'To apply options to a single interface, '
            'set ethtool_opts.iface_name.'),

        ('migration_destination_timeout', '21600',
            'Maximum time the destination waits for the migration to finish.'),

        ('migration_progress_timeout', '240',
            'Maximum time the source host waits during a migration in case '
            'that there is no progress. If the time has passed, the migration '
            'will be aborted.'),

        ('migration_max_time_per_gib_mem', '64',
            'The maximum time in seconds per GiB memory a migration may take '
            'before the migration will be aborted by the source host. '
            'Setting this value to 0 will disable this feature.'),

        ('migration_listener_timeout', '30',
            'Time to wait (in seconds) for migration destination to start '
            'listening before migration begins.'),

        ('migration_max_bandwidth', '52',
            'Local VDSM setting of the maximum bandwidth for sending '
            'migrations, in MiBps. 0 means libvirt\'s default, '
            'which is unlimited since v0.10.x. '
            'This value is used, if no maximal bandwidth is requested '
            'by Engine while initiating the migration.'),

        ('migration_monitor_interval', '10',
            'How often (in seconds) should the monitor thread pulse, 0 means '
            'the thread is disabled.'),

        ('hidden_nics', 'w*,usb*',
            'Comma-separated list of fnmatch-patterns for host nics to be '
            'hidden from vdsm.'),

        ('hidden_bonds', '',
            'Comma-separated list of fnmatch-patterns for host bonds to be '
            'hidden from vdsm.'),

        ('hidden_vlans', '',
            'Comma-separated list of fnmatch-patterns for host vlans to be '
            'hidden from vdsm. vlan names must be in the format "dev.VLANID" '
            '(e.g. eth0.100, em1.20, eth2.200). '
            'vlans with alternative names must be hidden from vdsm '
            '(e.g. eth0.10-fcoe, em1.myvlan100, vlan200)'),

        ('migration_downtime', '500',
            'Maximum allowed downtime for live migration in milliseconds '
            '(anything below 100ms is ignored) if you do not care about '
            'liveness of migration, set to a very high value, such as '
            '600000.'),

        ('migration_downtime_delay', '100',
            'Timespan in seconds per GiB of RAM, used on the source side '
            'to reach incrementally the final value of migration_downtime. '),

        ('migration_downtime_steps', '5',
            'Incremental steps used to reach migration_downtime.'),

        ('max_outgoing_migrations', '2',
            'Maximum concurrent outgoing migrations'),

        ('max_incoming_migrations', '2',
            'Maximum concurrent incoming migrations'),

        ('migration_retry_timeout', '10',
            'Time (in sec) to wait before retrying failed migration.'),

        ('sys_shutdown_timeout', '120',
            'Destroy and shutdown timeouts (in sec) before completing the '
            'action.'),

        ('user_shutdown_timeout', '30',
            'Grace period (seconds) to let guest user close his '
            'applications before shutdown.'),

        ('guest_agent_timeout', '30',
            'Time (in sec) to wait for oVirt guest agent.'),

        ('guest_lifecycle_event_reply_timeout', '10',
            'Time (in sec) to wait for the guest agent to reply on lifecycle'
            ' events (such as before_migration/before_hibernation'),

        ('vm_command_timeout', '60',
            'Time to wait (in seconds) for vm to respond to a monitor '
            'command, 30 secs is a nice default. Set to 300 if the vm is '
            'expected to freeze during cluster failover.'),

        ('hotunplug_timeout', '30',
            'Time to wait (in seconds) for a VM to detach its disk'),

        ('hotunplug_check_interval', '1',
            'Time to wait (in seconds) between consecutive checks for device'
            'removal'),

        ('vm_watermark_interval', '2',
            'How often should we check drive watermark on block storage for '
            'automatic extension of thin provisioned volumes (seconds).'),

        ('vm_sample_interval', '15', None),

        ('vm_sample_jobs_interval', '15', None),

        ('host_sample_stats_interval', '15', None),

        ('ssl', 'true',
            'Whether to use ssl encryption and authentication.'),

        ('vds_responsiveness_timeout', '60', None),

        ('vdsm_nice', '-5', None),

        ('qemu_drive_cache', 'none', None),

        ('fake_kvm_support', 'false', None),

        ('fake_kvm_architecture', 'x86_64',
            'Choose the target architecture of the fake KVM mode'),

        ('fake_kvm_memory', '0', 'Set memory of fake KVM hosts. '
         'Set to \'0\' to use supplied memory value'),

        ('fake_vmstats_enable', 'false', 'Enable reporting of fake VM stats.'),

        ('fake_sriov_enable', 'false',
         'Enable reporting of fake SR-IOV devices.'),

        ('dpdk_enable', 'false',
         'Enable experimental dpdk support'),

        ('http_enable', 'true', 'Enable the http server'),

        ('enable_lldp', 'true', 'Enable LLDP'),

        ('jsonrpc_enable', 'true', 'Enable the JSON RPC server'),

        ('broker_enable', 'false', 'Enable outgoing connection to broker'),

        ('report_host_threads_as_cores', 'false',
            'Count each cpu hyperthread as an individual core'),

        ('libvirt_env_variable_debug', '',
            'Control libvirt logging behavior'),

        ('libvirt_env_variable_log_filters', '',
            'Specify the log filters to track libvirt calls'),

        ('libvirt_env_variable_log_outputs', '',
            'Specify the output to track libvirt calls'),

            'Local path to the transient disks repository.'),

        ('ssl_protocol', 'sslv23',
            'SSL protocol used by encrypted connection'),

        ('ssl_excludes', '',
            'Comma separated protocol values as defined in '
            'https://docs.python.org/2/library/ssl.html. '
            'e.g. OP_NO_TLSv1_2 '
            'Only TLSv1.2+ are supported (depends on underlying openssl '
            'version).'),

        ('ssl_ciphers', '',
            'By default we use empty to use python default ciphers set. '
            'If one is willing to use more secure ciphers one can use '
            'HIGH or other cipher strings as defined in '
            'https://www.openssl.org/docs/man1.0.2/apps/ciphers.html.'),

        ('verify_client_cert', 'false',
            'Enables whether to verify client fqdn or ip stored '
            'in a certificate.'),

        ('connection_stats_timeout', '3600',
            'Time in seconds defining how frequently we log transport stats'),

        ('cpu_affinity', 'auto',
            'Use the special string value "auto" (default value) '
            'to make Vdsm pick the first online core, starting with the '
            'second logical core. '
            'If only the first logical core is online, Vdsm will use it. '
            'To explicitely select the CPU cores on which VDSM is allowed to '
            'run, use a comma separated list of CPU cores, expressed as '
            'integers starting from zero. '
            'To disable the affinity, allowing Vdsm to run on all the '
            'online cores, use the empty value. '
            'Valid examples: "auto", "1", "0,1", ""'),

        ('migration_create_timeout', '600',
            'Time in seconds defining how long we are going to wait for '
            'create migration response.'),

        ('host_numa_scheduling', 'true',
            'Enable implicit scheduling of VMs to properly match numa '
            'topology. Explicit settings sent from engine override '
            'the option.'),

        ('timeout_engine_clear_vms', '15',
            'How many seconds should VDSM arbitrarily hold the '
            'shutdown sequence and wait for Engine confirming '
            'that VMs are down. The timeout is split into two'
            'parts: two seconds are used in the very end to'
            'allow for passing final state from host to engine,'
            'the rest is used to wait when VMs are shutting down.'),

        ('vm_kill_paused_time', '80',
            'How many seconds to wait before killing VMs paused due to an I/O '
            'error. Only VMs explicitly marked as killable by Engine will be '
            'killed, the value does not have any effect on other VMs. '
            'The value should be close to sanlock kill interval and in any '
            'case greater than 0 (to tolerate short disturbances) and '
            'less than 300 (Engine monitoring interval).'),

        ('time_sync_snapshot_enable', 'false',
            'Enable guest time synchronization after snapshot.'
            'This flag can be set when creating snapshots of large Virtual '
            'Machines where the delay that occurs during processing is large.'
            'When this flag is enabled an attempt shall be made to '
            'synchronize the Guest Time  during these types of lengthy '
            'pauses. Currently the default value is false for backward '
            'compatibility and for those users who may not want Guest Time '
            'Synchronization enabled due to concerns pertaining to '
            'performance, etc.'),

        ('time_sync_cont_enable', 'false',
            'Enable guest time synchronization after un-pausing. '
            'This flag can be set when various operations cause large '
            'delays during processing not including creating snapshots '
            'which has a separate flag nor resumption after suspension '
            'which always attempts to synchronize the Guest Time. Relevant '
            'operations may include Replication, out of disk space '
            'scenarios, Domain State Change Monitoring delays, etc.'
            'Currently the default value is false for backward '
            'compatibility and for those users who may not want Guest Time '
            'Synchronization enabled due to concerns pertaining to '
            'performance, etc.'),
    ]),

    ('rpc', [

        ('worker_threads', '8',
            'Number of worker threads to serve jsonrpc server.'),

        ('tasks_per_worker', '10',
            'Max number of tasks which can be queued per workers.'),

        ('worker_timeout', '60',
            'Timeout in seconds for the jsonrpc workers.'),
    ]),

    ('mom', [


        ('socket_path', '/var/run/vdsm/mom-vdsm.sock',
            'path of the UNIX domain socket used to '
            'communicate with MOM'),

        ('tuning_policy', '01-parameters',
            'name of the mom policy to be updated from '
            'updatePolicyParameters API call'),

    ]),

    ('irs', [

        ('irs_enable', 'true', None),

        ('repository', '/rhev/data-center',
            'Image repository.'),

        ('hsm_tasks', '%(repository)s/hsm-tasks', None),

        ('images', '/images', None),

        ('irsd', '%(images)s/irsd', None),

        ('volume_utilization_percent', '50',
            'Together with volume_utilization_chunk_mb, set the minimal free '
            'space before a thin provisioned block volume is extended. Use '
            'lower values to extend earlier.'),

        ('volume_utilization_chunk_mb', '1024',
            'Size of extension chunk in megabytes, and together with '
            'volume_utilization_percent, set the free space limit. Use higher '
            'values to extend in bigger chunks.'),

        ('enable_block_threshold_event', 'true',
            'Use events, instead of polling, to check the write threshold '
            'on thin-provisioned block-based drives.'),

        ('vol_size_sample_interval', '60',
            'How often should the volume size be checked (seconds).'),

        ('scsi_rescan_maximal_timeout', '30',
            'The maximal number of seconds to wait for scsi scan to return.'),

        ('udev_settle_timeout', '5',
            'Maximum number of seconds to wait until udev events are '
            'processed. Used after rescanning iSCSI and FC connections, '
            'after connecting to iSCSI target, and after mounting and '
            'umounting file systems.'),

        ('sd_health_check_delay', '10',
            'Storage domain health check delay, the amount of seconds to '
            'wait between two successive run of the domain health check.'),

        ('nfs_mount_options', 'soft,nosharecache',
            'NFS mount options, comma-separated list (NB: no white space '
            'allowed!)'),


        ('lock_cmd', 'spmprotect.sh', None),

        ('free_lock_cmd', 'spmstop.sh', None),

        ('thread_pool_size', '10',
            'The number of threads to allocate to the task manager.'),

        ('max_tasks', '500', None),

        ('lvm_dev_whitelist', '', None),

        ('md_backup_versions', '30', None),


        ('maximum_allowed_pvs', '8',
            'The number of PVs per VG has a hard-coded limit of 10.'),

        ('repo_stats_cache_refresh_timeout', '300', None),

        ('task_resource_default_timeout', '120000', None),

        ('prepare_image_timeout', '600000', None),

        ('gc_blocker_force_collect_interval', '60', None),

        ('maximum_domains_in_pool', '100',
            'Process pool configuration.'),

        ('process_pool_timeout', '60', None),

        ('max_ioprocess_idle_time', '60',
            'TTL of an unused IOProcess instance'),

        ('process_pool_max_slots_per_domain', '10', None),

        ('process_pool_max_queued_slots_per_domain', '10', None),

        ('iscsi_default_ifaces', 'default',
            'Comma seperated ifaces to connect with. '
            'i.e. iser,default'),

        ('use_volume_leases', 'false',
            'Whether to use the volume leases or not.'),

        ('progress_interval', '30',
            'Time to wait (in seconds) between consecutive progress reports '
            'during long operations such as copying images (default 30)'),

        ('qcow2_compat', '0.10',
            'Recent qemu-img supports two incompatible qcow2 versions. '
            'We use 0.10 format by default so hosts with older qemu '
            'can consume images created by newer versions. '
            'See https://bugzilla.redhat.com/1139707 '
            '(supported versions: 0.10, 1.1)'),

        ('zero_method', 'blkdiscard',
            'The name of the method that is used to zero volumes. '
            'The options are: '
            '- blkdiscard - uses a "blkdiscard --zeroout" command. '
            '- dd - uses a "dd" command. Recommended only if there are issues '
            'with "blkdiscard". '
            'Note that when the underlying storage supports "write same", '
            'blkdiscard is more efficient than dd in terms of zeroing '
            'duration and network usage.'),

        ('zero_block_size_mb', '1',
            'The block size used when zeroing a device using the "dd" '
            'zero_method. This does not affect the "blkdiscard" '
            'zero_method which uses a constant block size. A legal value '
            'is an integer between 1 and 64 (default 1).'),
    ]),

    ('multipath', [

        ('blacklist', '',
            'Comma-separated list of multipath devices WWIDs that should '
            'not be managed by vdsm. When a hypervisor boots from SAN, the '
            'multipath devices used by the hypervisor must be configured '
            'to queue I/O when all paths have failed, and vdsm must not '
            'manage them. Example: 36001405472912345,360014054954321'),
    ]),

    ('jobs', [
        ('autodelete_delay', '3600',
            'Automatically delete completed jobs from memory after the '
            'specified delay (in seconds).  When this value is negative '
            'autodelete will be disabled.'),
    ]),

    ('addresses', [

        ('management_port', '54321',
            'Port on which the vdsmd XMPRPC server listens to network '
            'clients.'),

        ('management_ip', '::',
            'IP address on which the vdsmd server listens to network '
            'clients. '
            'Set to "0.0.0.0" to listen only on IPv4. '
            'Set to "::" to listen on both IPv4 & IPv6.'),

        ('broker_address', '127.0.0.1',
            'Address where the broker is listening at. Use an empty string '
            'for none'),

        ('broker_port', '5445',
            'Port where the broker is listening at.'),

        ('request_queues',
            'jms.topic.vdsm_requests,jms.topic.vdsm_irs_requests',
            'Queues for vdsm to subscribe to'),

        ('event_queue', 'jms.queue.events',
            'Queue used for events'),
    ]),

    ('sampling', [
        ('enable', 'true', 'enable or disable the monitoring subsystem'),

        ('periodic_workers', '4',
            'Number of worker threads to serve the periodic tasks.'
            ' This is for internal usage and may change without warning'),

        ('periodic_task_per_worker', '100',
            'Max number of tasks which can be queued on workers.'
            ' This is for internal usage and may change without warning'),

        ('max_workers', '30',
            'Maximum number of worker threads to serve the periodic tasks '
            'at the same time.'),

        ('collectd_enable', 'false',
            'Collect the VM samples using collectd, not using libvirt '
            'directly.'),

        ('collectd_sock_path', '/var/run/collectd-unixsock',
            'Unix domain socket to connect to collectd (enable the '
            'collectd "unixsock" plugin!)'),

        ('external_vm_lookup_interval', '60',
            'Number of seconds between lookups for external VMs.'),
    ]),

    ('metrics', [
        ('enabled', 'true',
            'Enable metrics collection (default true)'),

        ('collector_address', 'localhost',
            'Metrics collector address (default localhost)'),

        ('collector_type', 'statsd',
            'Metrics collector type (supporting statsd or hawkular)'),

        ('queue_size', '100',
            'Number of metrics messages to queue if collector is not'
            ' responsive. When the queue is full, oldest messages are'
            ' dropped. Used only by hawkular-client collector (default 100)'),
    ]),

    ('devel', [

        ('cpu_profile_enable', 'false',
            'Enable whole process profiling (requires yappi profiler).'),

        ('cpu_profile_filename', '/var/run/vdsm/vdsmd.prof',
            'Profile file name (/var/run/vdsm/vdsmd.prof)'),

        ('cpu_profile_format', 'pstat',
            'Profile file format (pstat, callgrind, ystat)'),

        ('cpu_profile_builtins', 'false',
            'Profile builtin functions used by standard Python modules. '
            'false by default.'),

        ('cpu_profile_clock', 'cpu',
            'Sets the underlying clock type (cpu, wall)'),

        ('memory_profile_enable', 'false',
            'Enable whole process profiling (requires dowser profiler).'),

        ('memory_profile_port', '9090',
            'Port on which the dowser Web UI will be reachable.'),

        ('manhole_enable', 'false',
            'Enable manhole debugging service (requires manhole package).'),

        ('coverage_enable', 'false',
            'Enable code coverage (requires python-coverage package). '
            'false by default. Use environment file /etc/sysconfig/vdsm to '
            'set COVERAGE_PROCESS_START and COVERAGE_FILE variables.'),

        ('health_monitor_enable', 'false',
            'Enable Vdsm health monitoring.'),

        ('health_check_interval', '60',
            'Number of seconds to wait between health checks.'),

        ('m2c_debug_enable', 'false',
            'Enable state information about the SSL connections which is by '
            'default logged to stderr.'),

        ('api_strict_mode', 'false',
            'Enable exception throwing when rpc data is not correct.'),

        ('xml_minimal_changes', 'true',
            'Perform minimal updates to the domain XML when starting a VM.'),
    ]),

    ('gluster', [

        ('allowed_replica_counts', '1,3',
            'Only replica 1 and 3 are supported. This configuration is for '
            'development only. Value is comma delimeted.'),

        ('enable_4k_storage', '1',
            "Enable support for gluster storage with 4k sector size. When "
            "set to 'true', storage sector size is detected when creating "
            "a storage domain. When set to 'false', storage with 4k sector "
            "size cannot be used. (default 1)."),

    ]),

    ('performance', [

        ('use_dynamic_hugepages', 'false',
            'Enable VDSM to automatically allocate and deallocate hugepages '
            'as needed to accomodate it\'s VMs. This option does not conflict '
            'with preallocated pages but rather extends it by making sure the '
            'reserved pages aren\'t touched by VDSM and free preallocated '
            'pages are used for VMs'),

        ('use_preallocated_hugepages', 'true',
            'Enable usage of hugepages that are allocated prior to VMs start. '
            'If enabled, the VM can use available preallocated hugepages up '
            'to it\'s RAM size. See also reserved_hugepage_count and '
            'reserved_hugepage_size. Only hugepages of the same size as VMs '
            'hugepage size are considered.'),

        ('reserved_hugepage_count', '0',
            'Number of hugepages to reserve (when use_preallocated_hugepages '
            'is enabled). Those pages will not be touched by VDSM.'),

        ('reserved_hugepage_size', 'none',
            'Size of the hugepages to reserve (when reserved_hugepage_count '
            'is > 0). None means system\'s default size.'),
    ]),

    ('v2v', [

        ('kvm2ovirt_buffer_size', '1048576',
                'Size of the buffer (in bytes) used by kvm2ovirt when '
                'transferring data from source libvirt. It may be necessary '
                'to tweak the size when communicating with old libvirt or '
                'for performance tuning.'),
    ]),

    ('guest_agent', [
        ('enable_qga_poller', 'true',
            'Enable or disable the QEMU-GA poller'),

        ('periodic_workers', '4',
            'Number of worker threads to serve the periodic tasks.'
            ' This is for internal usage and may change without warning'),

        ('periodic_task_per_worker', '100',
            'Max number of tasks which can be queued on workers.'
            ' This is for internal usage and may change without warning'),

        ('max_workers', '30',
            'Maximum number of worker threads to serve the periodic tasks '
            'at the same time.'),

        ('cleanup_period', '3600',
            'How often do the household cleaning and free data about VMs'
            ' that are no longer running.'),

        ('qga_command_timeout', '1',
            'Time (in sec) to wait for completion of single call to QEMU'
            ' Guest Agent.'
            ' This is for internal usage and may change without warning'),

        ('qga_task_timeout', '10',
            'Time (in sec) to wait for completion of periodic task.'
            ' After this time the task is stopped and worker is discarded.'
            ),

        ('qga_info_period', '300',
            'Period (in sec) with which to query the information about'
            '  installed QEMU Guest Agent.'),

        ('qga_sysinfo_period', '120',
            'Period (in sec) for gathering information about system version,'
            ' installed applications, and some configuration that does not'
            ' change too often.'),

        ('qga_active_users_period', '10',
            'Period (in sec) for gathering information about active users.'),

        ('qga_disk_info_period', '300',
            'Period (in sec) for gathering filesystem information and disk'
            ' mapping.'),

    ]),
]


def set_defaults(config):
    for section, keylist in parameters:
        config.add_section(section)
        for key, value, comment in keylist:
            config.set(section, key, value)


def print_config():

    print(twp.fill("VDSM Sample Configuration"))
    print('')

    for section, keylist in parameters:
        print("[%s]\n" % section)

        for key, value, comment in keylist:
            if comment:
                print(twp.fill(comment))
            print(twp.fill("%s = %s" % (key, value)))
            print('')


def load(name):
    cfg = configparser.ConfigParser()
    set_defaults(cfg)
    read_configs(cfg, name)
    return cfg


def read_configs(cfg, name):
    default_conf = os.path.join(_SYSCONFDIR, name, name + '.conf')
    cfg.read(default_conf)

    dropins = []
    for path in _DROPPIN_BASES:
        pattern = os.path.join(path, name, name + '.conf.d', '*.conf')
        dropins.extend(glob.glob(pattern))

    dropins.sort(key=os.path.basename)
    cfg.read(dropins)


config = load('vdsm')

if __name__ == '__main__':
    print_config()
