# @summary # Validate the server state based on predefined checks. # # The class generates or removes the validation script for the # state of the server. The resulting script can be automatically # invoked by AWS SSM after unattended patching. # # A hiera example: # # ```yaml # server_patching::validate::ensure: present # server_patching::validate::services: # - name: open-vm-tools.service # active: true # - name: openipmi.service # active: false # server_patching::validate::processes: # - name: falcond # running: true # server_patching::validate::urls: # - url: https://netdb.stanford.edu/status-3654hkfjd7fhbd # status: 200 # - url: https://netdb.stanford.edu # status: 302 # server_patching::validate::ports: # - port: 22 # proto: tcp # ip_ver: ipv4 # listening: true # - port: 23 # proto: tcp # ip_ver: ipv4 # listening: false # server_patching::validate::mounts: # - /home # - /mnt/data # server_patching::validate::exports: # - /share/raw_data # - /share/processed_data # server_patching::validate::zfs_pools: # - pool1 # - pool2 # ``` # # @param ensure # Deploy or remove the validation script. # # @param validation_script # Location of the validation script on the system. # # @param use_remctl # Whether to create a remctl for validation script or not. # # @param services # Array of hashes, where each hash is describing a service and # its desired state. # # @option services [String] :name # The name of the service to check. # # @option services [Boolean] :active # Desired state of the service: `true` if the service should be running or # `false` if the service should be stopped, disabled, masked or really failed. # Defaults to `true`. # # @param processes # Array of hashes, where each hash describes the name of a process # and whether it is supposed to be running. # # @option processes [String] :name # The name of the process to check. # # @option processes [Boolean] :running # The desired state of the process, `true` if the process should be running # or `false` if it is not supposed to. Defaults to `true`. # # @option processes [Boolean] :command # Search string for a command line arguments of a process. # # @param urls # Array of hashes, where each hash describes the web URL # and the HTTP status code it is supposed to return # # @option urls [Stdlib::HTTPUrl] :url # The HTTP URL to check. # # @option urls [Integer] :status # The HTTP status code :url is expected to return. Defaults to `200`. # # @option urls [Integer] :resolve_to # Force the domain specified in a URL to resolve to this IP address. # # @param ports # Array of hashes, where each hash contains a port number, protocol, # IP protocol version (IPv4/IPv6) and whether anything is expected # to be listening on it. # # @option ports [Stdlib::Port] :port # Port number to check. # # @option ports [Enum['tcp','udp']] :proto # Protocol TCP or UDP which is to be used for the check. Defaults to `tcp`. # # @option ports [Enum['ipv4','ipv6']] :ip_ver # Version of IP protocol to use for the check, IPv4 or IPv6. Defaults to `ipv4`. # # @option ports [Boolean] :listenting # `true`, if something is expected to listed on this port or `false` if # the port is not supposed to respond. Defaults to `true`. # # @param mounts # Array of mounts to be checked for presence. # # @param exports # Array of NFS exports to be checked for presence. Only local exports are checked. # # @param zfs_pools # Array of ZFS pools to be checked for presence. # # @example # include server_patching::validate # class server_patching::validate ( Enum['absent','present'] $ensure = 'present', Stdlib::Unixpath $validation_script = '/usr/local/bin/validate.sh', Array[Struct[{ 'name' => String, 'active' => Optional[Boolean]}]] $services = [], Array[Struct[{ 'name' => String, 'command' => Optional[String], 'running' => Optional[Boolean]}]] $processes = [], Array[Struct[{ 'url' => Stdlib::HTTPUrl, 'resolve_to' => Optional[Stdlib::IP::Address], 'status' => Optional[Integer[100,510]]}]] $urls = [], Array[Struct[{ 'port' => Stdlib::Port, 'proto' => Optional[Enum['tcp','udp']], 'ip_ver' => Optional[Enum['ipv4','ipv6']], 'listening' => Optional[Boolean]}]] $ports = [], Array[Stdlib::Unixpath] $mounts = [], Array[Stdlib::Unixpath] $exports = [], Array[String] $zfs_pools = [], ) { if [$services, $processes, $urls, $ports, $mounts, $exports, $zfs_pools].any |$param| { !empty($param) } { concat { $validation_script: ensure => $ensure, mode => '0700', } concat::fragment { 'bash-header': target => $validation_script, order => '01', content => epp('server_patching/validate/header.epp'), } concat::fragment { 'bash-footer': target => $validation_script, order => '50', content => epp('server_patching/validate/footer.epp'), } if !empty($services) { # By default we want services running $_services = $services.map |$service| { { 'active' => true } + $service } concat::fragment { 'validate-services': target => $validation_script, order => '01', content => epp('server_patching/validate/service.epp', { 'services' => $_services }), } } if !empty($processes) { # By default we want processes running $_processes = $processes.map |$process| { { 'running' => true } + $process } concat::fragment { 'validate-processes': target => $validation_script, order => '02', content => epp('server_patching/validate/process.epp', { 'processes' => $_processes }), } } if !empty($urls) { # By default we expect URLs to return HTTP status code 200 $_urls = $urls.map |$url| { { 'status' => 200 } + $url } concat::fragment { 'validate-urls': target => $validation_script, order => '03', content => epp('server_patching/validate/urls.epp', { 'urls' => $_urls }), } } if !empty($ports) { # By default we want to check TCP ports over IPv4 and expect them to respond. $_ports = $ports.map |$port| { { 'proto' => 'tcp', 'ip_ver' => 'ipv4', 'listening' => true } + $port } concat::fragment { 'validate-ports': target => $validation_script, order => '04', content => epp('server_patching/validate/ports.epp', { 'ports' => $_ports }), } } if !empty($mounts) { concat::fragment { 'validate-mounts': target => $validation_script, order => '05', content => epp('server_patching/validate/mount.epp', { 'mounts' => $mounts }), } } if !empty($exports) { concat::fragment { 'validate-exports': target => $validation_script, order => '06', content => epp('server_patching/validate/export.epp', { 'exports' => $exports }), } } if !empty($zfs_pools) { concat::fragment { 'validate-zpools': target => $validation_script, order => '07', content => epp('server_patching/validate/zpool.epp', { 'zfs_pools' => $zfs_pools }), } } } else { # If no checks are defined, no reason to keep an empty # validation script around. file { $validation_script: ensure => absent } } }