diff --git a/roles/grafana/README.md b/roles/grafana/README.md index 4b49f6a4..4f629374 100644 --- a/roles/grafana/README.md +++ b/roles/grafana/README.md @@ -31,34 +31,21 @@ All variables which can be overridden are stored in [defaults/main.yml](defaults | `grafana_apt_arch` | {{ 'arm64' if ansible_architecture == 'aarch64' else 'amd64' }} | Apt architecture | | `grafana_apt_repo` | deb [arch={{ grafana_apt_arch }} signed-by=/usr/share/keyrings/grafana.key] https://apt.grafana.com/ {{ grafana_apt_release_channel }} main | Apt repository string | | `grafana_apt_key` | https://apt.grafana.com/gpg.key | Apt repository gpg key | -| `grafana_instance` | {{ ansible_fqdn \| default(ansible_host) \| default(inventory_hostname) }} | Grafana instance name | -| `grafana_logs_dir` | /var/log/grafana | Path to logs directory | -| `grafana_data_dir` | /var/lib/grafana | Path to database directory | -| `grafana_address` | 0.0.0.0 | Address on which Grafana listens | -| `grafana_port` | 3000 | port on which Grafana listens | +| `grafana_ini.instance_name` | {{ ansible_fqdn \| default(ansible_host) \| default(inventory_hostname) }} | Grafana instance name | +| `grafana_ini.paths.logs` | /var/log/grafana | Path to logs directory | +| `grafana_ini.paths.data` | /var/lib/grafana | Path to database directory | +| `grafana_ini.server.http_addr` | 0.0.0.0 | Address on which Grafana listens | +| `grafana_ini.server.http_port` | 3000 | port on which Grafana listens | | `grafana_cap_net_bind_service` | false | Enables the use of ports below 1024 without root privileges by leveraging the 'capabilities' of the linux kernel. read: http://man7.org/linux/man-pages/man7/capabilities.7.html | -| `grafana_url` | "http://{{ grafana_address }}:{{ grafana_port }}" | Full URL used to access Grafana from a web browser | +| `grafana_ini.server.root_url` | "http://{{ grafana_ini.server.http_addr }}:{{ grafana_ini.server.http_port }}" | Full URL used to access Grafana from a web browser | | `grafana_api_url` | "{{ grafana_url }}" | URL used for API calls in provisioning if different from public URL. See [this issue](https://github.com/cloudalchemy/ansible-grafana/issues/70). | -| `grafana_domain` | "{{ ansible_fqdn \| default(ansible_host) \| default('localhost') }}" | setting is only used in as a part of the `root_url` option. Useful when using GitHub or Google OAuth | -| `grafana_server` | { protocol: http, enforce_domain: false, socket: "", cert_key: "", cert_file: "", enable_gzip: false, static_root_path: public, router_logging: false } | [server](http://docs.grafana.org/installation/configuration/#server) configuration section | -| `grafana_security` | { admin_user: admin, admin_password: "" } | [security](http://docs.grafana.org/installation/configuration/#security) configuration section | -| `grafana_database` | { type: sqlite3 } | [database](http://docs.grafana.org/installation/configuration/#database) configuration section | -| `grafana_welcome_email_on_sign_up` | false | Send welcome email after signing up | -| `grafana_users` | { allow_sign_up: false, auto_assign_org_role: Viewer, default_theme: dark } | [users](http://docs.grafana.org/installation/configuration/#users) configuration section | -| `grafana_auth` | {} | [authorization](http://docs.grafana.org/installation/configuration/#auth) configuration section | +| `grafana_ini.server.domain` | "{{ ansible_fqdn \| default(ansible_host) \| default('localhost') }}" | setting is only used in as a part of the `root_url` option. Useful when using GitHub or Google OAuth | +| `grafana_ini.server` | { protocol: http, enforce_domain: false, socket: "", cert_key: "", cert_file: "", enable_gzip: false, static_root_path: public, router_logging: false } | [server](http://docs.grafana.org/installation/configuration/#server) configuration section | +| `grafana_ini.security` | { admin_user: admin, admin_password: "" } | [security](http://docs.grafana.org/installation/configuration/#security) configuration section | +| `grafana_ini.database` | { type: sqlite3 } | [database](http://docs.grafana.org/installation/configuration/#database) configuration section | +| `grafana_ini.users` | { allow_sign_up: false, auto_assign_org_role: Viewer, default_theme: dark } | [users](http://docs.grafana.org/installation/configuration/#users) configuration section | +| `grafana_ini.auth` | {} | [authorization](http://docs.grafana.org/installation/configuration/#auth) configuration section | | `grafana_ldap` | {} | [ldap](http://docs.grafana.org/installation/ldap/) configuration section. group_mappings are expanded, see defaults for example | -| `grafana_session` | {} | [session](http://docs.grafana.org/installation/configuration/#session) management configuration section | -| `grafana_analytics` | {} | Google [analytics](http://docs.grafana.org/installation/configuration/#analytics) configuration section | -| `grafana_smtp` | {} | [smtp](http://docs.grafana.org/installation/configuration/#smtp) configuration section | -| `grafana_alerting` | { execute_alerts: true } | [alerting](http://docs.grafana.org/installation/configuration/#alerting) configuration section, require Grafana v10 and below | -| `grafana_unified_alerting` | { enabled: true } | [unified_alerting](https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/#unified_alerting) configuration section, require Grafana v11+ | -| `grafana_log` | {} | [log](http://docs.grafana.org/installation/configuration/#log) configuration section | -| `grafana_metrics` | {} | [metrics](http://docs.grafana.org/installation/configuration/#metrics) configuration section | -| `grafana_tracing` | {} | [tracing](http://docs.grafana.org/installation/configuration/#tracing) configuration section | -| `grafana_snapshots` | {} | [snapshots](http://docs.grafana.org/installation/configuration/#snapshots) configuration section | -| `grafana_image_storage` | {} | [image storage](http://docs.grafana.org/installation/configuration/#external-image-storage) configuration section | -| `grafana_date_formats` | {} | [date formats](http://docs.grafana.org/installation/configuration/#date_formats) configuration section | -| `grafana_feature_toggles` | {} | [feature toggles](http://docs.grafana.org/installation/configuration/#feature_toggles) configuration section | | `grafana_dashboards` | [] | List of dashboards which should be imported | | `grafana_dashboards_dir` | "dashboards" | Path to a local directory containing dashboards files in `json` format | | `grafana_datasources` | [] | List of datasources which should be configured | @@ -109,18 +96,6 @@ grafana_alert_notifications: uid: channel2 ``` -**NOTE 2**: setting the `http_addr`,`http_port`,`domain` and `root_url` parameters under the `grafana_server` variable has no effect, the `grafana_address`, `grafana_port`, `grafana_domain` and `grafana_url` values are used instead ( from [defaults/main.yml](defaults/main.yml) or as set variables). -An example snippet: -```yaml -grafana_domain: "{{ inventory_hostname }}" -grafana_url: "https://{{ inventory_hostname }}:3000" -grafana_address: 0.0.0.0 -grafana_port: 3000 - -grafana_server: - enforce_domain: false -``` - ## Supported CPU Architectures Historically packages were taken from different channels according to CPU architecture. Specifically, armv6/armv7 and aarch64/arm64 packages were via [unofficial packages distributed by fg2it](https://github.com/fg2it/grafana-on-raspberry). Now that Grafana publishes official ARM builds, all packages are taken from the official [Debian/Ubuntu](http://docs.grafana.org/installation/debian/#installing-on-debian-ubuntu) or [RPM](http://docs.grafana.org/installation/rpm/) packages. @@ -136,9 +111,10 @@ Fill in the admin password field with your choice, the Grafana web page won't as roles: - role: grafana.grafana.grafana vars: - grafana_security: - admin_user: admin - admin_password: enter_your_secure_password + grafana_ini: + security: + admin_user: admin + admin_password: enter_your_secure_password ``` diff --git a/roles/grafana/defaults/main.yml b/roles/grafana/defaults/main.yml index 958fc4c0..e483a8a5 100644 --- a/roles/grafana/defaults/main.yml +++ b/roles/grafana/defaults/main.yml @@ -19,92 +19,92 @@ grafana_use_provisioning: true # Should the provisioning be kept synced. If true, previous provisioned objects will be removed if not referenced anymore. grafana_provisioning_synced: false -grafana_instance: "{{ ansible_fqdn | default(ansible_host) | default(inventory_hostname) }}" - -grafana_logs_dir: "/var/log/grafana" -grafana_data_dir: "/var/lib/grafana" - -grafana_address: "0.0.0.0" -grafana_port: 3000 # To enable the use of ports below 1024 for unprivileged processes linux needs to set CAP_NET_BIND_SERVICE. # This has some security implications, and should be a conscious choice. # Get informed by reading: http://man7.org/linux/man-pages/man7/capabilities.7.html grafana_cap_net_bind_service: false -# External Grafana address. Variable maps to "root_url" in grafana server section -grafana_url: "http://{{ grafana_address }}:{{ grafana_port }}" -grafana_api_url: "{{ grafana_url }}" -grafana_domain: "{{ ansible_fqdn | default(ansible_host) | default('localhost') }}" - -# Additional options for grafana "server" section -# This section WILL omit options for: http_addr, http_port, domain, and root_url, as those settings are set by variables listed before -grafana_server: - protocol: http - enforce_domain: false - socket: "" - cert_key: "" - cert_file: "" - enable_gzip: false - static_root_path: public - router_logging: false - serve_from_sub_path: false - -# Variables correspond to ones in grafana.ini configuration file -# Security -grafana_security: - admin_user: admin - admin_password: "" -# secret_key: "" -# login_remember_days: 7 -# cookie_username: grafana_user -# cookie_remember_name: grafana_remember -# disable_gravatar: true -# data_source_proxy_whitelist: - -# Database setup -grafana_database: - type: sqlite3 -# host: 127.0.0.1:3306 -# name: grafana -# user: root -# password: "" -# url: "" -# ssl_mode: disable -# path: grafana.db -# max_idle_conn: 2 -# max_open_conn: "" -# log_queries: "" - -# Remote cache -grafana_remote_cache: {} - -# User management and registration -grafana_welcome_email_on_sign_up: false -grafana_users: - allow_sign_up: false - # allow_org_create: true - # auto_assign_org: true - auto_assign_org_role: Viewer - # login_hint: "email or username" - default_theme: dark - # external_manage_link_url: "" - # external_manage_link_name: "" - # external_manage_info: "" - -# grafana authentication mechanisms -grafana_auth: {} -# disable_login_form: false -# oauth_auto_login: false -# disable_signout_menu: false -# signout_redirect_url: "" -# anonymous: -# org_name: "Main Organization" -# org_role: Viewer -# ldap: -# config_file: "/etc/grafana/ldap.toml" -# allow_sign_up: false -# basic: -# enabled: true +grafana_ini_default: + instance_name: "{{ ansible_fqdn | default(ansible_host) | default(inventory_hostname) }}" + + paths: + logs: "/var/log/grafana" + data: "/var/lib/grafana" + + server: + http_addr: "0.0.0.0" + http_port: 3000 + # External Grafana address. Variable maps to "root_url" in grafana server section + #root_url: "http://{{ grafana_ini.server.http_addr }}:{{ grafana_ini.server.http_port }}" + domain: "{{ ansible_fqdn | default(ansible_host) | default('localhost') }}" + + # Additional options for grafana "server" section + # This section WILL omit options for: http_addr, http_port, domain, and root_url, as those settings are set by variables listed before + protocol: http + enforce_domain: false + socket: "" + cert_key: "" + cert_file: "" + enable_gzip: false + static_root_path: public + router_logging: false + serve_from_sub_path: false + + # Variables correspond to ones in grafana.ini configuration file + # Security + security: + admin_user: admin + admin_password: "" + # secret_key: "" + # login_remember_days: 7 + # cookie_username: grafana_user + # cookie_remember_name: grafana_remember + # disable_gravatar: true + # data_source_proxy_whitelist: + + # Database setup + database: + type: sqlite3 + # host: 127.0.0.1:3306 + # name: grafana + # user: root + # password: "" + # url: "" + # ssl_mode: disable + # path: grafana.db + # max_idle_conn: 2 + # max_open_conn: "" + # log_queries: "" + + # User management and registration + users: + allow_sign_up: false + # allow_org_create: true + # auto_assign_org: true + auto_assign_org_role: Viewer + # login_hint: "email or username" + default_theme: dark + # external_manage_link_url: "" + # external_manage_link_name: "" + # external_manage_info: "" + + # grafana authentication mechanisms + auth: {} + # disable_login_form: false + # oauth_auto_login: false + # disable_signout_menu: false + # signout_redirect_url: "" + # anonymous: + # org_name: "Main Organization" + # org_role: Viewer + # ldap: + # config_file: "/etc/grafana/ldap.toml" + # allow_sign_up: false + # basic: + # enabled: true + + +grafana_api_url: "{{ grafana_ini.server.root_url }}" grafana_ldap: {} # verbose_logging: false @@ -145,99 +145,6 @@ grafana_ldap: {} # - group_dn: "cn=alternative_admins,ou=groups,dc=grafana,dc=org" # org_role: Admin -# Grafana KeyCloak auth -grafana_auth_generic_oauth: {} -# enabled: true -# name: "Keycloak-OAuth" -# allow_sign_up: true -# client_id: YOUR_APP_CLIENT_ID -# client_secret: YOUR_APP_CLIENT_SECRET -# scopes: "openid email profile offline_access roles" -# email_attribute_path: email -# login_attribute_path: username -# name_attribute_path: full_name -# auth_url: "https:///realms//protocol/openid-connect/auth" -# token_url: "https:///realms//protocol/openid-connect/token" -# api_url: "https:///realms//protocol/openid-connect/userinfo" - -grafana_session: {} -# provider: file -# provider_config: "sessions" - -grafana_analytics: {} -# reporting_enabled: true -# google_analytics_ua_id: "" - -# Set this for mail notifications -grafana_smtp: {} -# host: -# user: -# password: -# from_address: - -# Enable grafana unified alerting mechanism for grafana v11+ -grafana_unified_alerting: - enabled: true - -# REMOVED FROM Grafana v11+ -# Enable grafana alerting mechanism for grafana v10 and below -grafana_alerting: - execute_alerts: true -# error_or_timeout: 'alerting' -# nodata_or_nullvalues: 'no_data' -# concurrent_render_limit: 5 - -# Grafana logging configuration -grafana_log: -# mode: 'console file' -# level: info - -# Internal grafana metrics system -grafana_metrics: {} -# interval_seconds: 10 -# graphite: -# address: "localhost:2003" -# prefix: "prod.grafana.%(instance_name)s" - -# Distributed tracing options -grafana_tracing: {} -# address: "localhost:6831" -# always_included_tag: "tag1:value1,tag2:value2" -# sampler_type: const -# sampler_param: 1 - -grafana_snapshots: {} -# external_enabled: true -# external_snapshot_url: "https://snapshots-origin.raintank.io" -# external_snapshot_name: "Publish to snapshot.raintank.io" -# snapshot_remove_expired: true -# snapshot_TTL_days: 90 - -# External image store -grafana_image_storage: {} -# provider: gcs -# key_file: -# bucket: -# path: - -# Date format -grafana_date_formats: {} -# full_date: "DD-MM-YYYY HH:mm:ss" -# interval_second: "HH:mm:ss" -# interval_minute: "HH:mm" -# interval_hour: "DD/MM HH:mm" -# interval_day: "DD/MM" -# interval_month: "MM-YYYY" -# interval_year: "YYYY" -# use_browser_locale: true -# default_timezone: "browser" - -# Feature toggles -# List of feature toggles: https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/feature-toggles/#feature-toggles -grafana_feature_toggles: {} -# autoMigrateOldPanels: true -# regressionTransformation: true - ####### # Plugins from https://grafana.com/plugins grafana_plugins: [] @@ -297,8 +204,3 @@ grafana_api_keys: [] grafana_api_keys_dir: "{{ lookup('env', 'HOME') }}/grafana/keys" grafana_environment: {} - -# Panels configurations -grafana_panels: {} -# disable_sanitize_html: false -# enable_alpha: false diff --git a/roles/grafana/handlers/main.yml b/roles/grafana/handlers/main.yml index d457b426..c52b190b 100644 --- a/roles/grafana/handlers/main.yml +++ b/roles/grafana/handlers/main.yml @@ -10,7 +10,7 @@ - name: "Set privileges on provisioned dashboards" ansible.builtin.file: - path: "{{ grafana_data_dir }}/dashboards" + path: "{{ grafana_ini.paths.data }}/dashboards" recurse: true owner: "grafana" group: "grafana" @@ -20,7 +20,7 @@ - name: "Set privileges on provisioned dashboards directory" ansible.builtin.file: - path: "{{ grafana_data_dir }}/dashboards" + path: "{{ grafana_ini.paths.data }}/dashboards" state: "directory" recurse: false mode: "0755" diff --git a/roles/grafana/molecule/alternative/converge.yml b/roles/grafana/molecule/alternative/converge.yml index 56e1ba89..b8350325 100644 --- a/roles/grafana/molecule/alternative/converge.yml +++ b/roles/grafana/molecule/alternative/converge.yml @@ -6,24 +6,29 @@ - grafana.grafana.grafana vars: grafana_version: 6.2.5 - grafana_security: - admin_user: admin - admin_password: "password" - grafana_address: "127.0.0.1" - grafana_auth: - login_maximum_inactive_lifetime_days: 42 - disable_login_form: false - oauth_auto_login: false - disable_signout_menu: false - signout_redirect_url: "" - anonymous: - org_name: "Main Organization" - org_role: Viewer - ldap: - config_file: "/etc/grafana/ldap.toml" - allow_sign_up: false - basic: - enabled: true + grafana_ini: + security: + admin_user: admin + admin_password: "password" + server: + http_addr: "127.0.0.1" + auth: + login_maximum_inactive_lifetime_days: 42 + disable_login_form: false + oauth_auto_login: false + disable_signout_menu: false + signout_redirect_url: "" + anonymous: + org_name: "Main Organization" + org_role: Viewer + ldap: + config_file: "/etc/grafana/ldap.toml" + allow_sign_up: false + basic: + enabled: true + log: + mode: syslog + level: warn grafana_ldap: verbose_logging: false servers: @@ -100,6 +105,3 @@ tlsAuth: false tlsAuthWithCACert: false tlsSkipVerify: true - grafana_log: - mode: syslog - level: warn diff --git a/roles/grafana/molecule/default/converge.yml b/roles/grafana/molecule/default/converge.yml index 3d76ca1b..29b62293 100644 --- a/roles/grafana/molecule/default/converge.yml +++ b/roles/grafana/molecule/default/converge.yml @@ -5,6 +5,7 @@ roles: - grafana.grafana.grafana vars: - grafana_security: - admin_user: "admin" - admin_password: "password" + grafana_ini: + security: + admin_user: admin + admin_password: password diff --git a/roles/grafana/tasks/api_keys.yml b/roles/grafana/tasks/api_keys.yml index d6ca94b6..d54f4e37 100644 --- a/roles/grafana/tasks/api_keys.yml +++ b/roles/grafana/tasks/api_keys.yml @@ -10,8 +10,8 @@ - name: "Check api key list" ansible.builtin.uri: url: "{{ grafana_api_url }}/api/auth/keys" - user: "{{ grafana_security.admin_user }}" - password: "{{ grafana_security.admin_password }}" + user: "{{ grafana_ini.security.admin_user }}" + password: "{{ grafana_ini.security.admin_password }}" force_basic_auth: true return_content: true register: __existing_api_keys @@ -20,8 +20,8 @@ - name: "Create grafana api keys" ansible.builtin.uri: url: "{{ grafana_api_url }}/api/auth/keys" - user: "{{ grafana_security.admin_user }}" - password: "{{ grafana_security.admin_password }}" + user: "{{ grafana_ini.security.admin_user }}" + password: "{{ grafana_ini.security.admin_password }}" force_basic_auth: true method: POST body_format: json diff --git a/roles/grafana/tasks/configure.yml b/roles/grafana/tasks/configure.yml index ac45615b..8e3d8db0 100644 --- a/roles/grafana/tasks/configure.yml +++ b/roles/grafana/tasks/configure.yml @@ -15,13 +15,13 @@ - path: "/etc/grafana/provisioning/notifiers" - path: "/etc/grafana/provisioning/notification" - path: "/etc/grafana/provisioning/plugins" - - path: "{{ grafana_logs_dir }}" + - path: "{{ grafana_ini.paths.logs }}" owner: grafana - - path: "{{ grafana_data_dir }}" + - path: "{{ grafana_ini.paths.data }}" owner: grafana - - path: "{{ grafana_data_dir }}/dashboards" + - path: "{{ grafana_ini.paths.data }}/dashboards" owner: grafana - - path: "{{ grafana_data_dir }}/plugins" + - path: "{{ grafana_ini.paths.data }}/plugins" owner: grafana - name: "Create grafana main configuration file" @@ -37,24 +37,24 @@ - name: "Create grafana LDAP configuration file" ansible.builtin.template: src: "ldap.toml.j2" - dest: "{{ grafana_auth.ldap.config_file | default('/etc/grafana/ldap.toml') }}" + dest: "{{ grafana_ini.auth.ldap.config_file | default('/etc/grafana/ldap.toml') }}" owner: "root" group: "grafana" mode: "0640" no_log: "{{ 'false' if lookup('env', 'CI') else 'true' }}" notify: restart_grafana when: - - "'ldap' in grafana_auth" - - "'enabled' not in grafana_auth.ldap or grafana_auth.ldap.enabled" + - "'ldap' in grafana_ini.auth" + - "'enabled' not in grafana_ini.auth.ldap or grafana_ini.auth.ldap.enabled" - name: "Enable grafana socket" when: - - "grafana_server.protocol is defined and grafana_server.protocol == 'socket'" - - "grafana_server.socket | dirname != '/var/run'" + - "grafana_ini.server.protocol is defined and grafana_ini.server.protocol == 'socket'" + - "grafana_ini.server.socket | dirname != '/var/run'" block: - name: "Create grafana socket directory" ansible.builtin.file: - path: "{{ grafana_server.socket | dirname }}" + path: "{{ grafana_ini.server.socket | dirname }}" state: "directory" mode: "0775" owner: "grafana" @@ -74,7 +74,7 @@ capability: CAP_NET_BIND_SERVICE+ep state: present when: - - "grafana_port | int <= 1024" + - "grafana_ini.server.http_port | int <= 1024" - "grafana_cap_net_bind_service" - name: Create a directory for overrides.conf unit file if it does not exist @@ -83,7 +83,7 @@ state: directory mode: '0755' when: - - "grafana_port | int <= 1024" + - "grafana_ini.server.http_port | int <= 1024" - "grafana_cap_net_bind_service" - name: "Enable grafana to ports lower than port 1024 in systemd unitfile" @@ -95,7 +95,7 @@ AmbientCapabilities=CAP_NET_BIND_SERVICE CapabilityBoundingSet=CAP_NET_BIND_SERVICE when: - - "grafana_port | int <= 1024" + - "grafana_ini.server.http_port | int <= 1024" - "grafana_cap_net_bind_service" - name: "Enable and start Grafana systemd unit" diff --git a/roles/grafana/tasks/dashboards.yml b/roles/grafana/tasks/dashboards.yml index 3fedb1f4..115d679e 100644 --- a/roles/grafana/tasks/dashboards.yml +++ b/roles/grafana/tasks/dashboards.yml @@ -95,7 +95,7 @@ folder: '' type: file options: - path: "{{ grafana_data_dir }}/dashboards" + path: "{{ grafana_ini.paths.data }}/dashboards" backup: false owner: root group: grafana @@ -105,7 +105,7 @@ - name: "Register previously copied dashboards" ansible.builtin.find: - paths: "{{ grafana_data_dir }}/dashboards" + paths: "{{ grafana_ini.paths.data }}/dashboards" hidden: true patterns: - "*.json" @@ -115,7 +115,7 @@ - name: "Import grafana dashboards" ansible.builtin.copy: src: "{{ item }}" - dest: "{{ grafana_data_dir }}/dashboards/{{ item | basename }}" + dest: "{{ grafana_ini.paths.data }}/dashboards/{{ item | basename }}" owner: root group: grafana mode: "0640" diff --git a/roles/grafana/tasks/datasources.yml b/roles/grafana/tasks/datasources.yml index 70b11451..bcd24572 100644 --- a/roles/grafana/tasks/datasources.yml +++ b/roles/grafana/tasks/datasources.yml @@ -2,8 +2,8 @@ - name: "Ensure datasources exist (via API)" community.grafana.grafana_datasource: grafana_url: "{{ grafana_api_url }}" - grafana_user: "{{ grafana_security.admin_user }}" - grafana_password: "{{ grafana_security.admin_password }}" + grafana_user: "{{ grafana_ini.security.admin_user }}" + grafana_password: "{{ grafana_ini.security.admin_password }}" name: "{{ item.name }}" ds_url: "{{ item.url }}" ds_type: "{{ item.type }}" diff --git a/roles/grafana/tasks/main.yml b/roles/grafana/tasks/main.yml index 719e31a1..08a8f559 100644 --- a/roles/grafana/tasks/main.yml +++ b/roles/grafana/tasks/main.yml @@ -1,4 +1,7 @@ --- +- name: Inherit default vars + ansible.builtin.set_fact: + grafana_ini: "{{ grafana_ini_default | ansible.builtin.combine(grafana_ini, recursive=true) }}" - name: "Gather variables for each operating system" ansible.builtin.include_vars: "{{ distrovars }}" vars: @@ -67,9 +70,9 @@ - name: "Wait for grafana to start" ansible.builtin.wait_for: - host: "{{ grafana_address if grafana_server.protocol is undefined or grafana_server.protocol in ['http', 'https'] else omit }}" - port: "{{ grafana_port if grafana_server.protocol is undefined or grafana_server.protocol in ['http', 'https'] else omit }}" - path: "{{ grafana_server.socket | default() if grafana_server.protocol is defined and grafana_server.protocol == 'socket' else omit }}" + host: "{{ grafana_ini.server.http_addr if grafana_ini.server.protocol is undefined or grafana_ini.server.protocol in ['http', 'https'] else omit }}" + port: "{{ grafana_ini.server.http_port if grafana_ini.server.protocol is undefined or grafana_ini.server.protocol in ['http', 'https'] else omit }}" + path: "{{ grafana_ini.server.socket | default() if grafana_ini.server.protocol is defined and grafana_ini.server.protocol == 'socket' else omit }}" tags: - grafana_install - grafana_configure diff --git a/roles/grafana/tasks/plugins.yml b/roles/grafana/tasks/plugins.yml index 133624a0..13117c6a 100644 --- a/roles/grafana/tasks/plugins.yml +++ b/roles/grafana/tasks/plugins.yml @@ -3,14 +3,14 @@ ansible.builtin.find: file_type: directory recurse: false - paths: "{{ grafana_data_dir }}/plugins" + paths: "{{ grafana_ini.paths.data }}/plugins" register: __installed_plugins - name: "Install plugins" become: true ansible.builtin.command: - cmd: "grafana-cli --pluginsDir {{ grafana_data_dir }}/plugins plugins install {{ item }}" - creates: "{{ grafana_data_dir }}/plugins/{{ item }}" + cmd: "grafana-cli --pluginsDir {{ grafana_ini.paths.data }}/plugins plugins install {{ item }}" + creates: "{{ grafana_ini.paths.data }}/plugins/{{ item }}" loop: "{{ grafana_plugins | difference(__installed_plugins.files) }}" register: __plugin_install until: "__plugin_install is succeeded" diff --git a/roles/grafana/tasks/preflight.yml b/roles/grafana/tasks/preflight.yml index 60f10442..3d6a5ada 100644 --- a/roles/grafana/tasks/preflight.yml +++ b/roles/grafana/tasks/preflight.yml @@ -2,9 +2,34 @@ - name: "Check variable types" ansible.builtin.assert: that: - - "grafana_server is mapping" - - "grafana_database is mapping" - - "grafana_security is mapping" + - grafana_logs_dir is undefined + - grafana_data_dir is undefined + - grafana_server is undefined + - grafana_database is undefined + - grafana_security is undefined + - grafana_remote_cache is undefined + - grafana_welcome_email_on_sign_up is undefined + - grafana_users is undefined + - grafana_auth is undefined + - grafana_auth_generic_oauth is undefined + - grafana_session is undefined + - grafana_analytics is undefined + - grafana_smtp is undefined + - grafana_alerting is undefined + - grafana_log is undefined + - grafana_metrics is undefined + - grafana_tracing is undefined + - grafana_snapshots is undefined + - grafana_image_storage is undefined + - grafana_date_formats is undefined + - grafana_feature_toggles is undefined + - grafana_instance is undefined + - grafana_address is undefined + - grafana_port is undefined + - grafana_domain is undefined + - grafana_url is undefined + - grafana_panels is undefined + fail_msg: Check upgrade notes - name: "Fail when datasources aren't configured when dashboards are set to be installed" ansible.builtin.fail: @@ -13,17 +38,17 @@ - name: "Fail when grafana admin user isn't set" ansible.builtin.fail: - msg: "Please specify grafana admin user (grafana_security.admin_user)" + msg: "Please specify grafana admin user (grafana_ini.security.admin_user)" when: - - "grafana_security.admin_user == '' or - grafana_security.admin_user is not defined" + - "grafana_ini.security.admin_user == '' or + grafana_ini.security.admin_user is not defined" - name: "Fail when grafana admin password isn't set" ansible.builtin.fail: - msg: "Please specify grafana admin password (grafana_security.admin_password)" + msg: "Please specify grafana admin password (grafana_ini.security.admin_password)" when: - - "grafana_security.admin_password == '' or - grafana_security.admin_password is not defined" + - "grafana_ini.security.admin_password == '' or + grafana_ini.security.admin_password is not defined" - name: "Fail on incorrect variable types in datasource definitions" ansible.builtin.fail: @@ -35,26 +60,12 @@ - name: "Fail on bad database configuration" ansible.builtin.fail: msg: "Invalid database configuration. Please look at http://docs.grafana.org/installation/configuration/#database" - when: "( grafana_database.type == 'sqlite3' and grafana_database.url is defined ) or - ( grafana_database.type != 'sqlite3' and grafana_database.path is defined ) or - ( grafana_database.type == 'sqlite3' and grafana_database.host is defined ) or - ( grafana_database.type == 'sqlite3' and grafana_database.user is defined ) or - ( grafana_database.type == 'sqlite3' and grafana_database.password is defined ) or - ( grafana_database.type == 'sqlite3' and grafana_database.server_cert_name is defined )" - -- name: "Fail when grafana_server isn't properly configured" - ansible.builtin.assert: - that: item.option not in grafana_server - fail_msg: "Invalid grafana_server configuration parameter: {{ item.option }}. Use variable {{ item.role_var }} instead" - loop: - - option: http_addr - role_var: grafana_address - - option: http_port - role_var: grafana_port - - option: domain - role_var: grafana_domain - - option: root_url - role_var: grafana_url + when: "( grafana_ini.database.type == 'sqlite3' and grafana_ini.database.url is defined ) or + ( grafana_ini.database.type != 'sqlite3' and grafana_ini.database.path is defined ) or + ( grafana_ini.database.type == 'sqlite3' and grafana_ini.database.host is defined ) or + ( grafana_ini.database.type == 'sqlite3' and grafana_ini.database.user is defined ) or + ( grafana_ini.database.type == 'sqlite3' and grafana_ini.database.password is defined ) or + ( grafana_ini.database.type == 'sqlite3' and grafana_ini.database.server_cert_name is defined )" - name: "Fail when grafana_api_keys uses invalid role names" ansible.builtin.fail: @@ -62,11 +73,11 @@ when: "item.role not in ['Viewer', 'Editor', 'Admin']" loop: "{{ grafana_api_keys }}" -- name: "Fail when grafana_ldap isn't set when grafana_auth.ldap is" +- name: "Fail when grafana_ldap isn't set when grafana_ini.auth.ldap is" ansible.builtin.fail: - msg: "You need to configure grafana_ldap.servers and grafana_ldap.group_mappings when grafana_auth.ldap is set" + msg: "You need to configure grafana_ldap.servers and grafana_ldap.group_mappings when grafana_ini.auth.ldap is set" when: - - "'ldap' in grafana_auth" + - "'ldap' in grafana_ini.auth" - "grafana_ldap is not defined or ('servers' not in grafana_ldap or 'group_mappings' not in grafana_ldap)" - name: "Force grafana_use_provisioning to false if grafana_version is < 5.0 ( grafana_version is set to '{{ grafana_version }}' )" @@ -76,16 +87,16 @@ - "grafana_version != 'latest'" - "grafana_version is version_compare('5.0', '<')" -- name: "Fail if grafana_port is lower than 1024 and grafana_cap_net_bind_service is not true" +- name: "Fail if grafana_ini.server.http_port is lower than 1024 and grafana_cap_net_bind_service is not true" ansible.builtin.fail: msg: "Trying to use a port lower than 1024 without setting grafana_cap_net_bind_service." when: - - "grafana_port | int <= 1024" + - "grafana_ini.server.http_port | int <= 1024" - "not grafana_cap_net_bind_service" -- name: "Fail if grafana_server.socket not defined when in socket mode" +- name: "Fail if grafana_ini.server.socket not defined when in socket mode" ansible.builtin.fail: - msg: "You need to configure grafana_server.socket when grafana_server.protocol is set to 'socket'" + msg: "You need to configure grafana_ini.server.socket when grafana_ini.server.protocol is set to 'socket'" when: - - "grafana_server.protocol is defined and grafana_server.protocol == 'socket'" - - "grafana_server.socket is undefined or grafana_server.socket == ''" + - "grafana_ini.server.protocol is defined and grafana_ini.server.protocol == 'socket'" + - "grafana_ini.server.socket is undefined or grafana_ini.server.socket == ''" diff --git a/roles/grafana/templates/grafana.ini.j2 b/roles/grafana/templates/grafana.ini.j2 index 0abcbdf3..bf32674d 100644 --- a/roles/grafana/templates/grafana.ini.j2 +++ b/roles/grafana/templates/grafana.ini.j2 @@ -3,242 +3,18 @@ # http://docs.grafana.org/installation/configuration # https://github.com/grafana/grafana/blob/master/conf/sample.ini -app_mode = production -instance_name = {{ grafana_instance }} - -# Directories -[paths] -data = {{ grafana_data_dir }} -logs = {{ grafana_logs_dir }} -plugins = {{ grafana_data_dir }}/plugins -; datasources = conf/datasources - -# HTTP options -[server] -{% if grafana_server.protocol is undefined or grafana_server.protocol in ['http', 'https'] %} -http_addr = {{ grafana_address }} -http_port = {{ grafana_port }} -{% endif %} -domain = {{ grafana_domain }} -root_url = {{ grafana_url }} -{% for k,v in grafana_server.items() %} -{% if not k in ['http_addr', 'http_port', 'domain', 'root_url'] %} -{{ k }} = {{ v }} -{% endif %} -{% endfor %} - -# Database -[database] -{% for k,v in grafana_database.items() %} -{% if k == 'password' %} -{{ k }} = """{{ v }}""" -{% else %} -{{ k }} = {{ v }} -{% endif %} -{% endfor %} - -# Plugins -{% if grafana_plugins_ops is defined %} -[plugins] -{% for k,v in grafana_plugins_ops.items() %} -{{ k }} = {{ v }} -{% endfor %} -{% endif %} - -# Remote cache -[remote_cache] -{% for k,v in grafana_remote_cache.items() %} +{% for k, v in grafana_ini.items() %} +{% if v is not mapping %} {{ k }} = {{ v }} +{% endif %} {% endfor %} -# Security -[security] -{% for k,v in grafana_security.items() %} +{% for section, items in grafana_ini.items() %} +{% if items is mapping %} +[{{ section }}] +{% for k,v in items.items() %} {{ k }} = {{ v }} {% endfor %} -# Users management and registration -{% if grafana_users != {} %} -[users] -{% for k,v in grafana_users.items() %} -{{ k }} = {{ v }} -{% endfor %} -{% endif %} -[emails] -welcome_email_on_sign_up = {{ grafana_welcome_email_on_sign_up }} - -# Authentication -{% if grafana_auth != {} %} -[auth] -disable_login_form = {{ grafana_auth.disable_login_form | default('False') }} -oauth_auto_login = {{ grafana_auth.oauth_auto_login | default('False') }} -oauth_allow_insecure_email_lookup = {{ grafana_auth.oauth_allow_insecure_email_lookup | default('False') }} -disable_signout_menu = {{ grafana_auth.disable_signout_menu | default('False') }} -signout_redirect_url = {{ grafana_auth.signout_redirect_url | default('') }} -{% for section, options in grafana_auth.items() %} -{% if options is mapping %} -[auth.{{ section }}] -{% if "enabled" not in options %} -enabled = True -{% endif %} -{% for k, v in options.items() %} -{{ k }} = {{ v }} -{% endfor %} -{% else %} -{{ section }} = {{ options }} -{% endif %} -{% endfor %} -{% endif %} - -# Session -{% if grafana_session != {} %} -[session] -{% for k,v in grafana_session.items() %} -{{ k }} = {{ v }} -{% endfor %} -{% endif %} - -# Analytics -[analytics] -reporting_enabled = "{{ grafana_analytics.reporting_enabled | default(True) }}" -{% if grafana_analytics.google_analytics_ua_id is defined and grafana_analytics.google_analytics_ua_id != '' %} -google_analytics_ua_id = "{{ grafana_analytics.google_analytics_ua_id }}" -{% endif %} - -# Dashboards -[dashboards] -versions_to_keep = 20 - -[dashboards.json] -enabled = true -path = {{ grafana_data_dir }}/dashboards - -{% if grafana_version == 'latest' or grafana_version.split('.')[0]|int >= 11 %} -# Unified Alerting -[unified_alerting] -{% if grafana_unified_alerting != {} %} -{% for k,v in grafana_unified_alerting.items() %} -{{ k }} = {{ v }} -{% endfor %} -{% else %} -enabled = false -{% endif %} -{% endif %} - -{% if grafana_version != 'latest' and grafana_version.split('.')[0]|int < 11 %} -# Alerting -[alerting] -{% if grafana_alerting != {} %} -enabled = true -{% for k,v in grafana_alerting.items() %} -{% if k != 'enabled' %} -{{ k }} = {{ v }} -{% endif %} -{% endfor %} -{% else %} -enabled = false -{% endif %} -{% endif %} - -# SMTP and email config -{% if grafana_smtp != {} %} -[smtp] -enabled = True -{% for k,v in grafana_smtp.items() %} -{% if k == 'enabled' %}{% endif %} -{% if k == 'password' %} -{{ k }} = """{{ v }}""" -{% else %} -{{ k }} = {{ v }} -{% endif %} -{% endfor %} -{% endif %} - -# Logging -[log] -mode = {{ grafana_log.mode | default('console, file') }} -level = {{ grafana_log.level | default('info') }} - -# Metrics -[metrics] -{% if grafana_metrics != {} %} -enabled = true -interval_seconds = {{ grafana_metrics.interval_seconds | default(10) }} -{% if grafana_metrics.basic_auth_username is defined %} -basic_auth_username = {{ grafana_metrics.basic_auth_username }} -{% endif %} -{% if grafana_metrics.basic_auth_password is defined %} -basic_auth_password = """{{ grafana_metrics.basic_auth_password }}""" -{% endif %} -{% if grafana_metrics.graphite is defined %} -[metrics.graphite] -address = {{ grafana_metrics.graphite.address }} -prefix = {{ grafana_metrics.graphite.prefix }} -{% endif %} -{% else %} -enabled = false -{% endif %} - -# Tracing -{% if grafana_tracing != {} %} -[tracing.jaeger] -{% for k,v in grafana_tracing.items() %} -{{ k }} = {{ v }} -{% endfor %} -{% endif %} - -# Grafana.com configuration -[grafana_com] -url = https://grafana.com - -# Snapshots -{% if grafana_snapshots != {} %} -[snapshots] -{% for k,v in grafana_snapshots.items() %} -{{ k }} = {{ v }} -{% endfor %} -{% endif %} - -# External image storage -{% if grafana_image_storage != {} %} -[external_image_storage] -provider = {{ grafana_image_storage.provider }} -[external_image_storage.{{ grafana_image_storage.provider }}] -{% for k,v in grafana_image_storage.items() %} -{% if k != 'provider' %} -{{ k }} = {{ v }} -{% endif %} -{% endfor %} -{% endif %} - -# Panels -{% if grafana_panels != {} %} -[panels] -{% for k,v in grafana_panels.items() %} -{{ k }} = {{ v }} -{% endfor %} -{% endif %} - -# Date formats -{% if grafana_date_formats != {} %} -[date_formats] -{% for k,v in grafana_date_formats.items() %} -{{ k }} = {{ v }} -{% endfor %} -{% endif %} - -{% if grafana_feature_toggles != {} %} -# Feature toggles -[feature_toggles] -{% for k,v in grafana_feature_toggles.items() %} -{{ k }} = {{ v }} -{% endfor %} -{% endif %} - -# Oauth_Keycloack -{% if grafana_auth_generic_oauth != {} %} -[auth.generic_oauth] -{% for k,v in grafana_auth_generic_oauth.items() %} -{{ k }} = {{ v }} -{% endfor %} {% endif %} +{% endfor %} diff --git a/roles/grafana/templates/tmpfiles.j2 b/roles/grafana/templates/tmpfiles.j2 index 16dda1b9..fbf23f5d 100644 --- a/roles/grafana/templates/tmpfiles.j2 +++ b/roles/grafana/templates/tmpfiles.j2 @@ -1,2 +1,2 @@ {{ ansible_managed | comment }} -d {{ grafana_server.socket | dirname }} 0775 grafana grafana +d {{ grafana_ini.server.socket | dirname }} 0775 grafana grafana diff --git a/tests/integration/targets/alert_contact_point/tasks/main.yml b/tests/integration/targets/alert_contact_point/tasks/main.yml index a038d449..8ba5afaf 100644 --- a/tests/integration/targets/alert_contact_point/tasks/main.yml +++ b/tests/integration/targets/alert_contact_point/tasks/main.yml @@ -6,7 +6,9 @@ type: email settings: addresses: ops@mydomain.com,devs@mydomain.com - grafana_url: "{{ grafana_url }}" + grafana_ini: + server: + root_url: "{{ grafana_url }}" grafana_api_key: "{{ grafana_api_key }}" state: present register: add_result @@ -24,7 +26,9 @@ type: email settings: addresses: ops@mydomain.com,devs@mydomain.com - grafana_url: "{{ grafana_url }}" + grafana_ini: + server: + root_url: "{{ grafana_url }}" grafana_api_key: "{{ grafana_api_key }}" state: present register: idempotent_result @@ -42,7 +46,9 @@ type: email settings: addresses: "ops@mydomain.com,devs@mydomain.com,admin@mydomain.com" - grafana_url: "{{ grafana_url }}" + grafana_ini: + server: + root_url: "{{ grafana_url }}" grafana_api_key: "{{ grafana_api_key }}" state: present register: update_result @@ -60,7 +66,9 @@ type: email settings: addresses: "ops@mydomain.com,devs@mydomain.com,admin@mydomain.com" - grafana_url: "{{ grafana_url }}" + grafana_ini: + server: + root_url: "{{ grafana_url }}" grafana_api_key: "{{ grafana_api_key }}" state: absent register: delete_result diff --git a/tests/integration/targets/alert_notification_policy/tasks/main.yml b/tests/integration/targets/alert_notification_policy/tasks/main.yml index c88bb3f7..1e051fca 100644 --- a/tests/integration/targets/alert_notification_policy/tasks/main.yml +++ b/tests/integration/targets/alert_notification_policy/tasks/main.yml @@ -1,6 +1,8 @@ - name: Set Notification policy tree grafana.grafana.alert_notification_policy: - grafana_url: "{{ grafana_url }}" + grafana_ini: + server: + root_url: "{{ grafana_url }}" grafana_api_key: "{{ grafana_api_key }}" routes: [ { diff --git a/tests/integration/targets/dashboard/tasks/main.yml b/tests/integration/targets/dashboard/tasks/main.yml index 8b2f88b5..1e3ee485 100644 --- a/tests/integration/targets/dashboard/tasks/main.yml +++ b/tests/integration/targets/dashboard/tasks/main.yml @@ -12,7 +12,9 @@ refresh: 25s version: 0 overwrite: true - grafana_url: "{{ grafana_url }}" + grafana_ini: + server: + root_url: "{{ grafana_url }}" grafana_api_key: "{{ grafana_api_key }}" state: present register: result_present @@ -36,7 +38,9 @@ version: 0 refresh: 25s overwrite: true - grafana_url: "{{ grafana_url }}" + grafana_ini: + server: + root_url: "{{ grafana_url }}" grafana_api_key: "{{ grafana_api_key }}" state: absent register: result_absent diff --git a/tests/integration/targets/datasource/tasks/main.yml b/tests/integration/targets/datasource/tasks/main.yml index 16e5a4ae..cd80d2a5 100644 --- a/tests/integration/targets/datasource/tasks/main.yml +++ b/tests/integration/targets/datasource/tasks/main.yml @@ -12,7 +12,9 @@ id: 123 uid: ansibletest access: proxy - grafana_url: "{{ grafana_url }}" + grafana_ini: + server: + root_url: "{{ grafana_url }}" grafana_api_key: "{{ grafana_api_key }}" state: present register: create_result @@ -36,7 +38,9 @@ id: 123 uid: ansibletest access: proxy - grafana_url: "{{ grafana_url }}" + grafana_ini: + server: + root_url: "{{ grafana_url }}" grafana_api_key: "{{ grafana_api_key }}" state: absent register: delete_result diff --git a/tests/integration/targets/folder/tasks/main.yml b/tests/integration/targets/folder/tasks/main.yml index 14d66c3f..cebde0fd 100644 --- a/tests/integration/targets/folder/tasks/main.yml +++ b/tests/integration/targets/folder/tasks/main.yml @@ -4,7 +4,9 @@ title: Ansible Integration test uid: test123 overwrite: true - grafana_url: "{{ grafana_url }}" + grafana_ini: + server: + root_url: "{{ grafana_url }}" grafana_api_key: "{{ grafana_api_key }}" state: present register: create_result @@ -19,7 +21,9 @@ title: Ansible Integration test uid: test123 overwrite: true - grafana_url: "{{ grafana_url }}" + grafana_ini: + server: + root_url: "{{ grafana_url }}" grafana_api_key: "{{ grafana_api_key }}" state: absent register: delete_result @@ -35,7 +39,9 @@ title: Ansible Integration test uid: test123 overwrite: true - grafana_url: "{{ grafana_url }}" + grafana_ini: + server: + root_url: "{{ grafana_url }}" grafana_api_key: "{{ grafana_api_key }}" state: absent register: delete_result