spec/chef/cookbooks/monitoring/recipes/prometheus_spec.rb (565 lines of code) (raw):

require 'chef_helper' RSpec.describe 'monitoring::prometheus' do let(:prometheus_scrape_config) do { job_name: "prometheus", static_configs: [ { targets: [ "localhost:9090" ] } ] } end let(:nginx_scrape_config) do { job_name: "nginx", static_configs: [ { targets: [ "localhost:8060" ] } ] } end let(:redis_scrape_config) do { job_name: "redis", static_configs: [ { targets: [ "localhost:9121" ] } ] } end let(:postgres_scrape_config) do { job_name: "postgres", static_configs: [ { targets: [ "localhost:9187" ] } ] } end let(:node_scrape_config) do { job_name: "node", static_configs: [ { targets: [ "localhost:9100" ] } ] } end let(:workhorse_scrape_config) do { job_name: "gitlab-workhorse", static_configs: [ { targets: [ "localhost:9229" ] } ] } end let(:rails_scrape_config) do { job_name: "gitlab-rails", metrics_path: "/-/metrics", static_configs: [ { targets: [ "127.0.0.1:8080" ] } ], relabel_configs: [ { source_labels: [ "__address__" ], regex: "127.0.0.1:(.*)", replacement: "localhost:$1", target_label: "instance" } ] } end let(:sidekiq_scrape_config) do { job_name: "gitlab-sidekiq", static_configs: [ { targets: [ "127.0.0.1:8082" ] } ], relabel_configs: [ { source_labels: [ "__address__" ], regex: "127.0.0.1:(.*)", replacement: "localhost:$1", target_label: "instance" } ] } end let(:registry_scrape_config) do { job_name: "registry", static_configs: [ { targets: [ "localhost:5001" ] } ] } end let(:gitlab_exporter_scrape_config) do [ { job_name: "gitlab_exporter_database", metrics_path: "/database", static_configs: [ { targets: [ "localhost:9168" ] } ] }, { job_name: "gitlab_exporter_sidekiq", metrics_path: "/sidekiq", static_configs: [ { targets: [ "localhost:9168" ] } ] }, { job_name: "gitlab_exporter_ruby", metrics_path: "/ruby", static_configs: [ { targets: [ "localhost:9168" ] } ] } ] end let(:gitaly_scrape_config) do { job_name: "gitaly", static_configs: [ { targets: [ "localhost:9236" ] } ] } end let(:k8s_scrape_config) do [ { job_name: "kubernetes-cadvisor", scheme: "https", tls_config: { ca_file: "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt", insecure_skip_verify: true }, bearer_token_file: "/var/run/secrets/kubernetes.io/serviceaccount/token", kubernetes_sd_configs: [ { role: "node", api_server: "https://kubernetes.default.svc:443", tls_config: { ca_file: "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" }, bearer_token_file: "/var/run/secrets/kubernetes.io/serviceaccount/token" } ], relabel_configs: [ { action: "labelmap", regex: "__meta_kubernetes_node_label_(.+)" }, { target_label: "__address__", replacement: "kubernetes.default.svc:443" }, { source_labels: [ "__meta_kubernetes_node_name" ], regex: "(.+)", target_label: "__metrics_path__", replacement: "/api/v1/nodes/${1}/proxy/metrics/cadvisor", } ], metric_relabel_configs: [ { source_labels: [ "pod_name" ], target_label: "environment", regex: "(.+)-.+-.+" } ] }, { job_name: "kubernetes-nodes", scheme: "https", tls_config: { ca_file: "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt", insecure_skip_verify: true }, bearer_token_file: "/var/run/secrets/kubernetes.io/serviceaccount/token", kubernetes_sd_configs: [ { role: "node", api_server: "https://kubernetes.default.svc:443", tls_config: { ca_file: "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" }, bearer_token_file: "/var/run/secrets/kubernetes.io/serviceaccount/token" } ], relabel_configs: [ { action: "labelmap", regex: "__meta_kubernetes_node_label_(.+)" }, { target_label: "__address__", replacement: "kubernetes.default.svc:443" }, { source_labels: [ "__meta_kubernetes_node_name" ], regex: "(.+)", target_label: "__metrics_path__", replacement: "/api/v1/nodes/${1}/proxy/metrics", } ], metric_relabel_configs: [ { source_labels: [ "pod_name" ], target_label: "environment", regex: "(.+)-.+-.+" } ] }, { job_name: "kubernetes-pods", tls_config: { ca_file: "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt", insecure_skip_verify: true }, bearer_token_file: "/var/run/secrets/kubernetes.io/serviceaccount/token", kubernetes_sd_configs: [ { role: "pod", api_server: "https://kubernetes.default.svc:443", tls_config: { ca_file: "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" }, bearer_token_file: "/var/run/secrets/kubernetes.io/serviceaccount/token" } ], relabel_configs: [ { source_labels: [ "__meta_kubernetes_pod_annotation_prometheus_io_scrape" ], action: "keep", regex: "true" }, { source_labels: [ "__meta_kubernetes_pod_annotation_prometheus_io_path" ], action: "replace", target_label: "__metrics_path__", regex: "(.+)" }, { source_labels: [ "__address__", "__meta_kubernetes_pod_annotation_prometheus_io_port" ], action: "replace", regex: "([^:]+)(?::[0-9]+)?;([0-9]+)", replacement: "$1:$2", target_label: "__address__" }, { action: "labelmap", regex: "__meta_kubernetes_pod_label_(.+)" }, { source_labels: [ "__meta_kubernetes_namespace" ], action: "replace", target_label: "kubernetes_namespace" }, { source_labels: [ "__meta_kubernetes_pod_name" ], action: "replace", target_label: "kubernetes_pod_name" } ] } ] end let(:expected_prometheus_yml) do { global: { scrape_interval: "15s", scrape_timeout: "15s", external_labels: {} }, remote_read: [], remote_write: [], rule_files: [ "/var/opt/gitlab/prometheus/rules/*.rules" ], scrape_configs: [ prometheus_scrape_config, nginx_scrape_config, redis_scrape_config, postgres_scrape_config, node_scrape_config, workhorse_scrape_config, rails_scrape_config, sidekiq_scrape_config, registry_scrape_config, gitlab_exporter_scrape_config, gitaly_scrape_config, k8s_scrape_config ].flatten, alerting: { alertmanagers: [ { static_configs: [ { targets: [ "localhost:9093" ] } ] } ] } } end let(:chef_run) { ChefSpec::SoloRunner.new(step_into: %w(runit_service)).converge('gitlab::default') } let(:prometheus_yml_template) { chef_run.file('/var/opt/gitlab/prometheus/prometheus.yml') } let(:prometheus_yml_file_content) { ChefSpec::Renderer.new(chef_run, prometheus_yml_template).content } let(:prometheus_yml) { YAML.safe_load(prometheus_yml_file_content, aliases: true, symbolize_names: true) } let(:default_vars) do { 'SSL_CERT_DIR' => '/opt/gitlab/embedded/ssl/certs/', } end before do allow(Gitlab).to receive(:[]).and_call_original end context 'when prometheus is enabled' do let(:config_template) { chef_run.template('/opt/gitlab/sv/prometheus/log/config') } before do stub_gitlab_rb( alertmanager: { enable: true }, prometheus: { enable: true }, gitlab_exporter: { enable: true }, registry: { enable: true, debug_addr: 'localhost:5001' } ) end it_behaves_like 'enabled runit service', 'prometheus', 'root', 'root' it 'creates necessary env variable files' do expect(chef_run).to create_env_dir('/opt/gitlab/etc/prometheus/env').with_variables(default_vars) end it 'populates the files with expected configuration' do expect(config_template).to notify('ruby_block[reload_log_service]') expect(chef_run).to render_file('/opt/gitlab/sv/prometheus/run') .with_content { |content| expect(content).to match(/exec chpst -P/) expect(content).to match(/\/opt\/gitlab\/embedded\/bin\/prometheus/) expect(content).to match(/prometheus.yml/) } expect(prometheus_yml).to match(expected_prometheus_yml) expect(chef_run).to render_file('/opt/gitlab/sv/prometheus/log/run') .with_content(/svlogd -tt \/var\/log\/gitlab\/prometheus/) end it 'creates default set of directories' do expect(chef_run).to create_directory('/var/opt/gitlab/prometheus').with( owner: 'gitlab-prometheus', group: nil, mode: '0750' ) end it 'should create a gitlab-prometheus user and group' do expect(chef_run).to create_account('Prometheus user and group').with(username: 'gitlab-prometheus', groupname: 'gitlab-prometheus') end it 'sets a default listen address' do expect(chef_run).to render_file('/opt/gitlab/sv/prometheus/run') .with_content(/web.listen-address=localhost:9090/) end end context 'by default' do context 'with user provided settings' do it 'configures puma job' do expect(chef_run).to render_file('/var/opt/gitlab/prometheus/prometheus.yml') .with_content(%r{- job_name: gitlab-rails\s+metrics_path: "/-/metrics"\s+static_configs:\s+- targets:\s+- 127.0.0.1:8080}) end end end context 'when exporter scheme is https' do context 'when gitlab-exporter responds using TLS' do before do allow(::File).to receive(:exist?).and_call_original allow(::File).to receive(:exist?).with(%r{/tmp/server.(crt|key)}).and_return(true) stub_gitlab_rb( gitlab_exporter: { enable: true, tls_enabled: true, tls_cert_path: '/tmp/server.crt', tls_key_path: '/tmp/server.key', } ) end it 'populates the gitlab-exporter scrape config properly' do expected_config = gitlab_exporter_scrape_config.dup expected_config.each do |config| config.merge!( scheme: 'https', tls_config: { server_name: 'localhost', insecure_skip_verify: false } ) end generated_config = prometheus_yml[:scrape_configs].select { |item| item[:job_name].start_with?('gitlab_exporter') } expect(generated_config).to eq(expected_config) end end context 'when puma responds using TLS' do before do allow(::File).to receive(:exist?).and_call_original allow(::File).to receive(:exist?).with(%r{/tmp/server.(crt|key)}).and_return(true) stub_gitlab_rb( puma: { ssl_listen: '127.0.0.1', ssl_port: 9111, ssl_certificate: '/tmp/server.crt', ssl_certificate_key: '/tmp/server.key', } ) end it 'populates the rails scrape config properly' do expected_config = rails_scrape_config.dup expected_config.merge!( scheme: 'https', tls_config: { server_name: 'localhost', insecure_skip_verify: false }, static_configs: [ targets: [ "127.0.0.1:9111" ] ] ) generated_config = prometheus_yml[:scrape_configs].find { |item| item[:job_name] == 'gitlab-rails' } expect(generated_config).to eq(expected_config) end end end context 'rules directory' do context 'default settings' do it 'creates rules directory in correct location' do expect(chef_run).to create_directory("/var/opt/gitlab/prometheus/rules") expect(chef_run).to render_file("/var/opt/gitlab/prometheus/rules/node.rules") expect(chef_run).to render_file("/var/opt/gitlab/prometheus/rules/gitlab.rules") end end context 'user specified home directory' do before do stub_gitlab_rb( prometheus: { home: "/var/opt/gitlab/prometheus-bak" } ) end it 'creates rules directory in correct location' do expect(chef_run).to create_directory("/var/opt/gitlab/prometheus-bak/rules") expect(chef_run).to render_file("/var/opt/gitlab/prometheus-bak/rules/node.rules") expect(chef_run).to render_file("/var/opt/gitlab/prometheus-bak/rules/gitlab.rules") end end context 'user specified rules directory' do before do stub_gitlab_rb( prometheus: { rules_directory: "/var/opt/gitlab/prometheus/alert-rules" } ) end it 'creates rules directory in correct location' do expect(chef_run).to create_directory("/var/opt/gitlab/prometheus/alert-rules") expect(chef_run).to render_file("/var/opt/gitlab/prometheus/alert-rules/node.rules") expect(chef_run).to render_file("/var/opt/gitlab/prometheus/alert-rules/gitlab.rules") end end end context 'log directory and runit group' do context 'default values' do it_behaves_like 'enabled logged service', 'prometheus', true, { log_directory_owner: 'gitlab-prometheus' } end context 'custom values' do before do stub_gitlab_rb( prometheus: { log_group: 'fugee' } ) end it_behaves_like 'enabled logged service', 'prometheus', true, { log_directory_owner: 'gitlab-prometheus', log_group: 'fugee' } end end include_examples "consul service discovery", "prometheus", "prometheus" end