summaryrefslogtreecommitdiffstats
path: root/roles/openshift_logging
diff options
context:
space:
mode:
Diffstat (limited to 'roles/openshift_logging')
-rw-r--r--roles/openshift_logging/README.md6
-rw-r--r--roles/openshift_logging/files/generate-jks.sh12
-rw-r--r--roles/openshift_logging/tasks/generate_certs.yaml126
-rw-r--r--roles/openshift_logging/tasks/generate_jks.yaml98
-rw-r--r--roles/openshift_logging/tasks/install_curator.yaml2
-rw-r--r--roles/openshift_logging/tasks/install_elasticsearch.yaml2
-rw-r--r--roles/openshift_logging/tasks/install_kibana.yaml2
-rw-r--r--roles/openshift_logging/tasks/install_logging.yaml21
-rw-r--r--roles/openshift_logging/tasks/label_node.yaml27
-rw-r--r--roles/openshift_logging/tasks/main.yaml1
-rw-r--r--roles/openshift_logging/templates/curator.j26
-rw-r--r--roles/openshift_logging/templates/es.j26
-rw-r--r--roles/openshift_logging/templates/kibana.j26
13 files changed, 182 insertions, 133 deletions
diff --git a/roles/openshift_logging/README.md b/roles/openshift_logging/README.md
index 2cc2c48ee..856cfa2b9 100644
--- a/roles/openshift_logging/README.md
+++ b/roles/openshift_logging/README.md
@@ -6,6 +6,9 @@ This role is used for installing the Aggregated Logging stack. It should be run
a single host, it will create any missing certificates and API objects that the current
[logging deployer](https://github.com/openshift/origin-aggregated-logging/tree/master/deployer) does.
+This role requires that the control host it is run on has Java installed as part of keystore
+generation for Elasticsearch (it uses JKS) as well as openssl to sign certificates.
+
As part of the installation, it is recommended that you add the Fluentd node selector label
to the list of persisted [node labels](https://docs.openshift.org/latest/install_config/install/advanced_install.html#configuring-node-host-labels).
@@ -32,6 +35,7 @@ When both `openshift_logging_install_logging` and `openshift_logging_upgrade_log
- `openshift_logging_curator_log_level`: The log level for the Curator process. Defaults to 'ERROR'.
- `openshift_logging_curator_cpu_limit`: The amount of CPU to allocate to Curator. Default is '100m'.
- `openshift_logging_curator_memory_limit`: The amount of memory to allocate to Curator. Unset if not specified.
+- `openshift_logging_curator_nodeselector`: A map of labels (e.g. {"node":"infra","region":"west"} to select the nodes where the curator pod will land.
- `openshift_logging_kibana_hostname`: The Kibana hostname. Defaults to 'kibana.example.com'.
- `openshift_logging_kibana_cpu_limit`: The amount of CPU to allocate to Kibana or unset if not specified.
@@ -40,6 +44,7 @@ When both `openshift_logging_install_logging` and `openshift_logging_upgrade_log
- `openshift_logging_kibana_proxy_cpu_limit`: The amount of CPU to allocate to Kibana proxy or unset if not specified.
- `openshift_logging_kibana_proxy_memory_limit`: The amount of memory to allocate to Kibana proxy or unset if not specified.
- `openshift_logging_kibana_replica_count`: The number of replicas Kibana should be scaled up to. Defaults to 1.
+- `openshift_logging_kibana_nodeselector`: A map of labels (e.g. {"node":"infra","region":"west"} to select the nodes where the pod will land.
- `openshift_logging_fluentd_nodeselector`: The node selector that the Fluentd daemonset uses to determine where to deploy to. Defaults to '"logging-infra-fluentd": "true"'.
- `openshift_logging_fluentd_cpu_limit`: The CPU limit for Fluentd pods. Defaults to '100m'.
@@ -64,6 +69,7 @@ When both `openshift_logging_install_logging` and `openshift_logging_upgrade_log
- `openshift_logging_es_pvc_prefix`: The prefix for the generated PVCs. Defaults to 'logging-es'.
- `openshift_logging_es_recover_after_time`: The amount of time ES will wait before it tries to recover. Defaults to '5m'.
- `openshift_logging_es_storage_group`: The storage group used for ES. Defaults to '65534'.
+- `openshift_logging_es_nodeselector`: A map of labels (e.g. {"node":"infra","region":"west"} to select the nodes where the pod will land.
When `openshift_logging_use_ops` is `True`, there are some additional vars. These work the
same as above for their non-ops counterparts, but apply to the OPS cluster instance:
diff --git a/roles/openshift_logging/files/generate-jks.sh b/roles/openshift_logging/files/generate-jks.sh
index 995ec0b98..9fe557f83 100644
--- a/roles/openshift_logging/files/generate-jks.sh
+++ b/roles/openshift_logging/files/generate-jks.sh
@@ -1,6 +1,10 @@
#! /bin/sh
set -ex
+function usage() {
+ echo Usage: `basename $0` cert_directory [logging_namespace] 1>&2
+}
+
function generate_JKS_chain() {
dir=${SCRATCH_DIR:-_output}
ADD_OID=$1
@@ -147,8 +151,14 @@ function createTruststore() {
-noprompt -alias sig-ca
}
-dir="$CERT_DIR"
+if [ $# -lt 1 ]; then
+ usage
+ exit 1
+fi
+
+dir=$1
SCRATCH_DIR=$dir
+PROJECT=${2:-logging}
if [[ ! -f $dir/system.admin.jks || -z "$(keytool -list -keystore $dir/system.admin.jks -storepass kspass | grep sig-ca)" ]]; then
generate_JKS_client_cert "system.admin"
diff --git a/roles/openshift_logging/tasks/generate_certs.yaml b/roles/openshift_logging/tasks/generate_certs.yaml
index e16071e46..740e490e1 100644
--- a/roles/openshift_logging/tasks/generate_certs.yaml
+++ b/roles/openshift_logging/tasks/generate_certs.yaml
@@ -85,133 +85,15 @@
loop_control:
loop_var: node_name
-- name: Check for jks-generator service account
- command: >
- {{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig get serviceaccount/jks-generator --no-headers -n {{openshift_logging_namespace}}
- register: serviceaccount_result
- ignore_errors: yes
- when: not ansible_check_mode
- changed_when: no
-
-- name: Create jks-generator service account
- command: >
- {{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig create serviceaccount jks-generator -n {{openshift_logging_namespace}}
- when: not ansible_check_mode and "not found" in serviceaccount_result.stderr
-
-- name: Check for hostmount-anyuid scc entry
- command: >
- {{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig get scc hostmount-anyuid -o jsonpath='{.users}'
- register: scc_result
- when: not ansible_check_mode
- changed_when: no
-
-- name: Add to hostmount-anyuid scc
- command: >
- {{ openshift.common.admin_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig policy add-scc-to-user hostmount-anyuid -z jks-generator -n {{openshift_logging_namespace}}
- when:
- - not ansible_check_mode
- - scc_result.stdout.find("system:serviceaccount:{{openshift_logging_namespace}}:jks-generator") == -1
-
-- name: Copy JKS generation script
- copy:
- src: generate-jks.sh
- dest: "{{generated_certs_dir}}/generate-jks.sh"
- check_mode: no
+- name: Creating necessary JKS certs
+ include: generate_jks.yaml
-- name: Generate JKS pod template
- template:
- src: jks_pod.j2
- dest: "{{mktemp.stdout}}/jks_pod.yaml"
- check_mode: no
- changed_when: no
-
-# check if pod generated files exist -- if they all do don't run the pod
-- name: Checking for elasticsearch.jks
- stat: path="{{generated_certs_dir}}/elasticsearch.jks"
- register: elasticsearch_jks
- check_mode: no
-
-- name: Checking for logging-es.jks
- stat: path="{{generated_certs_dir}}/logging-es.jks"
- register: logging_es_jks
- check_mode: no
-
-- name: Checking for system.admin.jks
- stat: path="{{generated_certs_dir}}/system.admin.jks"
- register: system_admin_jks
- check_mode: no
-
-- name: Checking for truststore.jks
- stat: path="{{generated_certs_dir}}/truststore.jks"
- register: truststore_jks
- check_mode: no
-
-- name: create JKS generation pod
- command: >
- {{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig create -f {{mktemp.stdout}}/jks_pod.yaml -n {{openshift_logging_namespace}} -o name
- register: podoutput
- check_mode: no
- when: not elasticsearch_jks.stat.exists or not logging_es_jks.stat.exists or not system_admin_jks.stat.exists or not truststore_jks.stat.exists
-
-- command: >
- {{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig get {{podoutput.stdout}} -o jsonpath='{.status.phase}' -n {{openshift_logging_namespace}}
- register: result
- until: result.stdout.find("Succeeded") != -1
- retries: 5
- delay: 10
- changed_when: no
- when: not elasticsearch_jks.stat.exists or not logging_es_jks.stat.exists or not system_admin_jks.stat.exists or not truststore_jks.stat.exists
-
-# check for secret/logging-kibana-proxy
-- command: >
- {{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig get secret/logging-kibana-proxy -n {{openshift_logging_namespace}} -o jsonpath='{.data.oauth-secret}'
- register: kibana_secret_oauth_check
- ignore_errors: yes
- changed_when: no
- check_mode: no
-
-- command: >
- {{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig get secret/logging-kibana-proxy -n {{openshift_logging_namespace}} -o jsonpath='{.data.session-secret}'
- register: kibana_secret_session_check
- ignore_errors: yes
- changed_when: no
- check_mode: no
-
-# check for oauthclient secret
-- command: >
- {{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig get oauthclient/kibana-proxy -n {{openshift_logging_namespace}} -o jsonpath='{.secret}'
- register: oauth_secret_check
- ignore_errors: yes
- changed_when: no
- check_mode: no
-
-# set or generate as needed
+# TODO: make idempotent
- name: Generate proxy session
set_fact: session_secret={{'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'|random_word(200)}}
check_mode: no
- when:
- - kibana_secret_session_check.stdout is not defined or kibana_secret_session_check.stdout == ''
-
-- name: Generate proxy session
- set_fact: session_secret={{kibana_secret_session_check.stdout | b64decode }}
- check_mode: no
- when:
- - kibana_secret_session_check.stdout is defined
- - kibana_secret_session_check.stdout != ''
+# TODO: make idempotent
- name: Generate oauth client secret
set_fact: oauth_secret={{'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'|random_word(64)}}
check_mode: no
- when: kibana_secret_oauth_check.stdout is not defined or kibana_secret_oauth_check.stdout == ''
- or oauth_secret_check.stdout is not defined or oauth_secret_check.stdout == ''
- or kibana_secret_oauth_check.stdout | b64decode != oauth_secret_check.stdout
-
-- name: Generate oauth client secret
- set_fact: oauth_secret={{kibana_secret_oauth_check.stdout | b64decode}}
- check_mode: no
- when:
- - kibana_secret_oauth_check is defined
- - kibana_secret_oauth_check.stdout != ''
- - oauth_secret_check.stdout is defined
- - oauth_secret_check.stdout != ''
- - kibana_secret_oauth_check.stdout | b64decode == oauth_secret_check.stdout
diff --git a/roles/openshift_logging/tasks/generate_jks.yaml b/roles/openshift_logging/tasks/generate_jks.yaml
new file mode 100644
index 000000000..c6e2ccbc0
--- /dev/null
+++ b/roles/openshift_logging/tasks/generate_jks.yaml
@@ -0,0 +1,98 @@
+---
+# check if pod generated files exist -- if they all do don't run the pod
+- name: Checking for elasticsearch.jks
+ stat: path="{{generated_certs_dir}}/elasticsearch.jks"
+ register: elasticsearch_jks
+ check_mode: no
+
+- name: Checking for logging-es.jks
+ stat: path="{{generated_certs_dir}}/logging-es.jks"
+ register: logging_es_jks
+ check_mode: no
+
+- name: Checking for system.admin.jks
+ stat: path="{{generated_certs_dir}}/system.admin.jks"
+ register: system_admin_jks
+ check_mode: no
+
+- name: Checking for truststore.jks
+ stat: path="{{generated_certs_dir}}/truststore.jks"
+ register: truststore_jks
+ check_mode: no
+
+- name: Create temp directory for doing work in
+ local_action: command mktemp -d /tmp/openshift-logging-ansible-XXXXXX
+ register: local_tmp
+ changed_when: False
+ check_mode: no
+
+- name: Create placeholder for previously created JKS certs to prevent recreating...
+ local_action: file path="{{local_tmp.stdout}}/elasticsearch.jks" state=touch mode="u=rw,g=r,o=r"
+ when: elasticsearch_jks.stat.exists
+ changed_when: False
+
+- name: Create placeholder for previously created JKS certs to prevent recreating...
+ local_action: file path="{{local_tmp.stdout}}/logging-es.jks" state=touch mode="u=rw,g=r,o=r"
+ when: logging_es_jks.stat.exists
+ changed_when: False
+
+- name: Create placeholder for previously created JKS certs to prevent recreating...
+ local_action: file path="{{local_tmp.stdout}}/system.admin.jks" state=touch mode="u=rw,g=r,o=r"
+ when: system_admin_jks.stat.exists
+ changed_when: False
+
+- name: Create placeholder for previously created JKS certs to prevent recreating...
+ local_action: file path="{{local_tmp.stdout}}/truststore.jks" state=touch mode="u=rw,g=r,o=r"
+ when: truststore_jks.stat.exists
+ changed_when: False
+
+- name: pulling down signing items from host
+ fetch:
+ src: "{{generated_certs_dir}}/{{item}}"
+ dest: "{{local_tmp.stdout}}/{{item}}"
+ flat: yes
+ with_items:
+ - ca.crt
+ - ca.key
+ - ca.serial.txt
+ - ca.crl.srl
+ - ca.db
+ when: not elasticsearch_jks.stat.exists or not logging_es_jks.stat.exists or not system_admin_jks.stat.exists or not truststore_jks.stat.exists
+
+- local_action: template src=signing.conf.j2 dest={{local_tmp.stdout}}/signing.conf
+ vars:
+ - top_dir: "{{local_tmp.stdout}}"
+ when: not elasticsearch_jks.stat.exists or not logging_es_jks.stat.exists or not system_admin_jks.stat.exists or not truststore_jks.stat.exists
+
+- name: Run JKS generation script
+ local_action: script generate-jks.sh {{local_tmp.stdout}} {{openshift_logging_namespace}}
+ check_mode: no
+ when: not elasticsearch_jks.stat.exists or not logging_es_jks.stat.exists or not system_admin_jks.stat.exists or not truststore_jks.stat.exists
+
+- name: Pushing locally generated JKS certs to remote host...
+ copy:
+ src: "{{local_tmp.stdout}}/elasticsearch.jks"
+ dest: "{{generated_certs_dir}}/elasticsearch.jks"
+ when: not elasticsearch_jks.stat.exists
+
+- name: Pushing locally generated JKS certs to remote host...
+ copy:
+ src: "{{local_tmp.stdout}}/logging-es.jks"
+ dest: "{{generated_certs_dir}}/logging-es.jks"
+ when: not logging_es_jks.stat.exists
+
+- name: Pushing locally generated JKS certs to remote host...
+ copy:
+ src: "{{local_tmp.stdout}}/system.admin.jks"
+ dest: "{{generated_certs_dir}}/system.admin.jks"
+ when: not system_admin_jks.stat.exists
+
+- name: Pushing locally generated JKS certs to remote host...
+ copy:
+ src: "{{local_tmp.stdout}}/truststore.jks"
+ dest: "{{generated_certs_dir}}/truststore.jks"
+ when: not truststore_jks.stat.exists
+
+- name: Cleaning up temp dir
+ local_action: file path="{{local_tmp.stdout}}" state=absent
+ changed_when: False
diff --git a/roles/openshift_logging/tasks/install_curator.yaml b/roles/openshift_logging/tasks/install_curator.yaml
index 8f2825552..fcfce4e1e 100644
--- a/roles/openshift_logging/tasks/install_curator.yaml
+++ b/roles/openshift_logging/tasks/install_curator.yaml
@@ -31,6 +31,7 @@
curator_cpu_limit: "{{openshift_logging_curator_cpu_limit }}"
curator_memory_limit: "{{openshift_logging_curator_memory_limit }}"
replicas: "{{curator_replica_count.stdout | default (0)}}"
+ curator_node_selector: "{{openshift_logging_curator_nodeselector | default({}) }}"
check_mode: no
changed_when: no
@@ -46,6 +47,7 @@
curator_cpu_limit: "{{openshift_logging_curator_ops_cpu_limit }}"
curator_memory_limit: "{{openshift_logging_curator_ops_memory_limit }}"
replicas: "{{curator_ops_replica_count.stdout | default (0)}}"
+ curator_node_selector: "{{openshift_logging_curator_ops_nodeselector | default({}) }}"
when: openshift_logging_use_ops
check_mode: no
changed_when: no
diff --git a/roles/openshift_logging/tasks/install_elasticsearch.yaml b/roles/openshift_logging/tasks/install_elasticsearch.yaml
index fbba46a35..9b1c004f2 100644
--- a/roles/openshift_logging/tasks/install_elasticsearch.yaml
+++ b/roles/openshift_logging/tasks/install_elasticsearch.yaml
@@ -33,6 +33,7 @@
volume_names: "{{es_pvc_pool | default([])}}"
pvc_claim: "{{(volume_names | length > item.0) | ternary(volume_names[item.0], None)}}"
deploy_name: "{{item.1}}"
+ es_node_selector: "{{openshift_logging_es_nodeselector | default({})}}"
with_indexed_items:
- "{{es_dc_pool | default([])}}"
check_mode: no
@@ -98,6 +99,7 @@
es_recover_after_nodes: "{{es_ops_recover_after_nodes}}"
es_recover_expected_nodes: "{{es_ops_recover_expected_nodes}}"
openshift_logging_es_recover_after_time: "{{openshift_logging_es_ops_recover_after_time}}"
+ es_node_selector: "{{openshift_logging_es_ops_nodeselector | default({})}}"
with_indexed_items:
- "{{es_dc_pool_ops | default([])}}"
when:
diff --git a/roles/openshift_logging/tasks/install_kibana.yaml b/roles/openshift_logging/tasks/install_kibana.yaml
index de4b018dd..f4df7de0c 100644
--- a/roles/openshift_logging/tasks/install_kibana.yaml
+++ b/roles/openshift_logging/tasks/install_kibana.yaml
@@ -35,6 +35,7 @@
kibana_proxy_cpu_limit: "{{openshift_logging_kibana_proxy_cpu_limit }}"
kibana_proxy_memory_limit: "{{openshift_logging_kibana_proxy_memory_limit }}"
replicas: "{{kibana_replica_count.stdout | default (0)}}"
+ kibana_node_selector: "{{openshift_logging_kibana_nodeselector | default({}) }}"
check_mode: no
changed_when: no
@@ -53,6 +54,7 @@
kibana_proxy_cpu_limit: "{{openshift_logging_kibana_ops_proxy_cpu_limit }}"
kibana_proxy_memory_limit: "{{openshift_logging_kibana_ops_proxy_memory_limit }}"
replicas: "{{kibana_ops_replica_count.stdout | default (0)}}"
+ kibana_node_selector: "{{openshift_logging_kibana_ops_nodeselector | default({}) }}"
when: openshift_logging_use_ops
check_mode: no
changed_when: no
diff --git a/roles/openshift_logging/tasks/install_logging.yaml b/roles/openshift_logging/tasks/install_logging.yaml
index af03e9371..a9699adb8 100644
--- a/roles/openshift_logging/tasks/install_logging.yaml
+++ b/roles/openshift_logging/tasks/install_logging.yaml
@@ -23,23 +23,30 @@
loop_control:
loop_var: install_component
+- find: paths={{ mktemp.stdout }}/templates patterns=*.yaml
+ register: object_def_files
+ changed_when: no
+
+- slurp: src={{item}}
+ register: object_defs
+ with_items: "{{object_def_files.files | map(attribute='path') | list | sort}}"
+ changed_when: no
+
- name: Create objects
include: oc_apply.yaml
vars:
- kubeconfig: "{{ mktemp.stdout }}/admin.kubeconfig"
- namespace: "{{ openshift_logging_namespace }}"
- - file_name: "{{ file }}"
- - file_content: "{{ lookup('file', file) | from_yaml }}"
- with_fileglob:
- - "{{ mktemp.stdout }}/templates/*.yaml"
+ - file_name: "{{ file.source }}"
+ - file_content: "{{ file.content | b64decode | from_yaml }}"
+ with_items: "{{ object_defs.results }}"
loop_control:
loop_var: file
when: not ansible_check_mode
- name: Printing out objects to create
- debug: msg="{{lookup('file', file)|quote}}"
- with_fileglob:
- - "{{mktemp.stdout}}/templates/*.yaml"
+ debug: msg={{file.content | b64decode }}
+ with_items: "{{ object_defs.results }}"
loop_control:
loop_var: file
when: ansible_check_mode
diff --git a/roles/openshift_logging/tasks/label_node.yaml b/roles/openshift_logging/tasks/label_node.yaml
index aecb5d81b..bd5073381 100644
--- a/roles/openshift_logging/tasks/label_node.yaml
+++ b/roles/openshift_logging/tasks/label_node.yaml
@@ -1,11 +1,34 @@
---
- command: >
{{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig get node {{host}}
+ -o jsonpath='{.metadata.labels}'
+ register: node_labels
+ when: not ansible_check_mode
+ changed_when: no
+
+- command: >
+ {{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig label node {{host}} {{label}}={{value}}
+ register: label_result
+ failed_when: label_result.rc == 1 and 'exists' not in label_result.stderr
+ when:
+ - value is defined
+ - node_labels.stdout is defined
+ - label not in node_labels.stdout
+ - unlabel is not defined or not unlabel
+ - not ansible_check_mode
+
+- command: >
+ {{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig get node {{host}}
-o jsonpath='{.metadata.labels.{{ label }}}'
register: label_value
- failed_when: label_value.rc == 1 and 'exists' not in label_value.stderr
- when: not ansible_check_mode
+ ignore_errors: yes
changed_when: no
+ when:
+ - value is defined
+ - node_labels.stdout is defined
+ - label in node_labels.stdout
+ - unlabel is not defined or not unlabel
+ - not ansible_check_mode
- command: >
{{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig label node {{host}} {{label}}={{value}} --overwrite
diff --git a/roles/openshift_logging/tasks/main.yaml b/roles/openshift_logging/tasks/main.yaml
index c4ec1b255..4c718805e 100644
--- a/roles/openshift_logging/tasks/main.yaml
+++ b/roles/openshift_logging/tasks/main.yaml
@@ -3,7 +3,6 @@
msg: Only one Fluentd nodeselector key pair should be provided
when: "{{ openshift_logging_fluentd_nodeselector.keys() | count }} > 1"
-
- name: Create temp directory for doing work in
command: mktemp -d /tmp/openshift-logging-ansible-XXXXXX
register: mktemp
diff --git a/roles/openshift_logging/templates/curator.j2 b/roles/openshift_logging/templates/curator.j2
index d3b5d33a2..de6258eaa 100644
--- a/roles/openshift_logging/templates/curator.j2
+++ b/roles/openshift_logging/templates/curator.j2
@@ -28,6 +28,12 @@ spec:
spec:
terminationGracePeriod: 600
serviceAccountName: aggregated-logging-curator
+{% if curator_node_selector is iterable and curator_node_selector | length > 0 %}
+ nodeSelector:
+{% for key, value in curator_node_selector.iteritems() %}
+ {{key}}: {{value}}
+{% endfor %}
+{% endif %}
containers:
-
name: "curator"
diff --git a/roles/openshift_logging/templates/es.j2 b/roles/openshift_logging/templates/es.j2
index 291589690..ec84c6b76 100644
--- a/roles/openshift_logging/templates/es.j2
+++ b/roles/openshift_logging/templates/es.j2
@@ -30,6 +30,12 @@ spec:
securityContext:
supplementalGroups:
- {{openshift_logging_es_storage_group}}
+{% if es_node_selector is iterable and es_node_selector | length > 0 %}
+ nodeSelector:
+{% for key, value in es_node_selector.iteritems() %}
+ {{key}}: {{value}}
+{% endfor %}
+{% endif %}
containers:
-
name: "elasticsearch"
diff --git a/roles/openshift_logging/templates/kibana.j2 b/roles/openshift_logging/templates/kibana.j2
index 1ec97701a..b42f62850 100644
--- a/roles/openshift_logging/templates/kibana.j2
+++ b/roles/openshift_logging/templates/kibana.j2
@@ -27,6 +27,12 @@ spec:
component: "{{component}}"
spec:
serviceAccountName: aggregated-logging-kibana
+{% if kibana_node_selector is iterable and kibana_node_selector | length > 0 %}
+ nodeSelector:
+{% for key, value in kibana_node_selector.iteritems() %}
+ {{key}}: {{value}}
+{% endfor %}
+{% endif %}
containers:
-
name: "kibana"