blob: 21f33a6a638a781f4cbfb38086d7836ed13ece6e [file] [log] [blame]
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
---
# This role will install Controller in group 'controllers' in the environment
# inventory
- import_tasks: docker_login.yml
- name: get controller name and index
set_fact:
controller_name: "{{ name_prefix ~ host_group.index(inventory_hostname) }}"
controller_index:
"{{ (controller_index_base|int) + host_group.index(inventory_hostname) }}"
- name: "pull the {{ docker.image.tag }} image of controller"
shell: "docker pull {{docker_registry}}{{ docker.image.prefix }}/controller:{{docker.image.tag}}"
when: docker_registry != ""
register: result
until: (result.rc == 0)
retries: "{{ docker.pull.retries }}"
delay: "{{ docker.pull.delay }}"
- name: ensure controller log directory is created with permissions
file:
path: "{{ whisk_logs_dir }}/{{ controller_name }}"
state: directory
mode: 0777
become: "{{ logs.dir.become }}"
# We need to create the file with proper permissions because the dir creation above
# does not result in a dir with full permissions in docker machine especially with macos mounts
- name: ensure controller log file is created with permissions
file:
path: "{{ whisk_logs_dir }}/{{ controller_name }}/{{ controller_name }}_logs.log"
state: touch
mode: 0777
when: environment_type is defined and environment_type == "docker-machine"
- name: ensure controller config directory is created with permissions
file:
path: "{{ controller.confdir }}/{{ controller_name }}"
state: directory
mode: 0777
become: "{{ controller.dir.become }}"
- name: copy jmxremote password file
when: jmx.enabled
template:
src: "jmxremote.password.j2"
dest: "{{ controller.confdir }}/{{ controller_name }}/jmxremote.password"
mode: 0777
- name: copy jmxremote access file
when: jmx.enabled
template:
src: "jmxremote.access.j2"
dest: "{{ controller.confdir }}/{{ controller_name }}/jmxremote.access"
mode: 0777
- name: "copy kafka truststore/keystore"
when: kafka.protocol == 'SSL'
copy:
src:
"{{openwhisk_home~'/ansible/roles/kafka/files/'~kafka.ssl.keystore.name}}"
dest: "{{ controller.confdir }}/{{ controller_name }}"
- name: copy nginx certificate keystore
when: controller.protocol == 'https'
copy:
src: files/{{ controller.ssl.keystore.name }}
mode: 0666
dest: "{{ controller.confdir }}/{{ controller_name }}"
become: "{{ controller.dir.become }}"
- name: copy certificates
when: controller.protocol == 'https'
copy:
src: "{{ openwhisk_home }}/ansible/roles/controller/files/{{ item }}"
mode: 0666
dest: "{{ controller.confdir }}/{{ controller_name }}"
with_items:
- "{{ controller.ssl.cert }}"
- "{{ controller.ssl.key }}"
become: "{{ controller.dir.become }}"
- name: check, that required databases exist
include_tasks: "{{ openwhisk_home }}/ansible/tasks/db/checkDb.yml"
vars:
dbName: "{{ item }}"
dbUser: "{{ db.credentials.controller.user }}"
dbPass: "{{ db.credentials.controller.pass }}"
with_items:
- "{{ db.whisk.actions }}"
- "{{ db.whisk.auth }}"
- "{{ db.whisk.activations }}"
- name: prepare controller port
set_fact:
controller_port: "{{ controller.basePort + (controller_index | int) }}"
ports_to_expose:
- "{{ controller.basePort + (controller_index | int) }}:8080"
- name: expose additional ports if jmxremote is enabled
when: jmx.enabled
vars:
jmx_remote_port: "{{ jmx.basePortController + (controller_index|int) }}"
jmx_remote_rmi_port:
"{{ jmx.rmiBasePortController + (controller_index|int) }}"
set_fact:
ports_to_expose: >-
{{ ports_to_expose }} +
[ '{{ jmx_remote_port }}:{{ jmx_remote_port }}' ] +
[ '{{ jmx_remote_rmi_port }}:{{ jmx_remote_rmi_port }}' ]
controller_args: >-
{{ controller.arguments }}
{{ jmx.jvmCommonArgs }}
-Djava.rmi.server.hostname={{ inventory_hostname }}
-Dcom.sun.management.jmxremote.rmi.port={{ jmx_remote_rmi_port }}
-Dcom.sun.management.jmxremote.port={{ jmx_remote_port }}
- name: Load config from template
set_fact:
openwhisk_config: "{{ lookup('template', 'config.j2') | b64encode }}"
- name: populate environment variables for controller
set_fact:
env:
"JAVA_OPTS":
-Xmx{{ controller.heap }}
-XX:+CrashOnOutOfMemoryError
-XX:+UseGCOverheadLimit
-XX:ErrorFile=/logs/java_error.log
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/logs
"CONTROLLER_OPTS": "{{ controller_args | default(controller.arguments) }}"
"JMX_REMOTE": "{{ jmx.enabled }}"
"OPENWHISK_ENCODED_CONFIG": "{{ openwhisk_config }}"
"PORT": "8080"
"TZ": "{{ docker.timezone }}"
"CONFIG_whisk_info_date": "{{ whisk.version.date }}"
"CONFIG_whisk_info_buildNo": "{{ docker.image.tag }}"
"KAFKA_HOSTS": "{{ kafka_connect_string }}"
"CONFIG_whisk_kafka_replicationFactor":
"{{ kafka.replicationFactor | default() }}"
"CONFIG_whisk_kafka_topics_cacheInvalidation_retentionBytes":
"{{ kafka_topics_cacheInvalidation_retentionBytes | default() }}"
"CONFIG_whisk_kafka_topics_cacheInvalidation_retentionMs":
"{{ kafka_topics_cacheInvalidation_retentionMS | default() }}"
"CONFIG_whisk_kafka_topics_cacheInvalidation_segmentBytes":
"{{ kafka_topics_cacheInvalidation_segmentBytes | default() }}"
"CONFIG_whisk_kafka_topics_completed_retentionBytes":
"{{ kafka_topics_completed_retentionBytes | default() }}"
"CONFIG_whisk_kafka_topics_completed_retentionMs":
"{{ kafka_topics_completed_retentionMS | default() }}"
"CONFIG_whisk_kafka_topics_completed_segmentBytes":
"{{ kafka_topics_completed_segmentBytes | default() }}"
"CONFIG_whisk_kafka_topics_health_retentionBytes":
"{{ kafka_topics_health_retentionBytes | default() }}"
"CONFIG_whisk_kafka_topics_health_retentionMs":
"{{ kafka_topics_health_retentionMS | default() }}"
"CONFIG_whisk_kafka_topics_health_segmentBytes":
"{{ kafka_topics_health_segmentBytes | default() }}"
"CONFIG_whisk_kafka_topics_prefix":
"{{ kafka.topicsPrefix }}"
"CONFIG_whisk_kafka_topics_userEvent_prefix":
"{{ kafka.topicsUserEventPrefix }}"
"CONFIG_whisk_kafka_common_securityProtocol":
"{{ kafka.protocol }}"
"CONFIG_whisk_kafka_common_sslTruststoreLocation":
"/conf/{{ kafka.ssl.keystore.name }}"
"CONFIG_whisk_kafka_common_sslTruststorePassword":
"{{ kafka.ssl.keystore.password }}"
"CONFIG_whisk_kafka_common_sslKeystoreLocation":
"/conf/{{ kafka.ssl.keystore.name }}"
"CONFIG_whisk_kafka_common_sslKeystorePassword":
"{{ kafka.ssl.keystore.password }}"
"CONFIG_whisk_couchdb_protocol": "{{ db.protocol }}"
"CONFIG_whisk_couchdb_host": "{{ db.host }}"
"CONFIG_whisk_couchdb_port": "{{ db.port }}"
"CONFIG_whisk_couchdb_username": "{{ db.credentials.controller.user }}"
"CONFIG_whisk_couchdb_password": "{{ db.credentials.controller.pass }}"
"CONFIG_whisk_couchdb_provider": "{{ db.provider }}"
"CONFIG_whisk_couchdb_databases_WhiskAuth": "{{ db.whisk.auth }}"
"CONFIG_whisk_couchdb_databases_WhiskEntity": "{{ db.whisk.actions }}"
"CONFIG_whisk_couchdb_databases_WhiskActivation":
"{{ db.whisk.activations }}"
"CONFIG_whisk_db_subjectsDdoc": "{{ db_whisk_subjects_ddoc | default() }}"
"CONFIG_whisk_db_actionsDdoc": "{{ db_whisk_actions_ddoc | default() }}"
"CONFIG_whisk_db_activationsDdoc": "{{ db_whisk_activations_ddoc | default() }}"
"CONFIG_whisk_db_activationsFilterDdoc": "{{ db_whisk_activations_filter_ddoc | default() }}"
"CONFIG_whisk_userEvents_enabled": "{{ user_events | default(false) | lower }}"
"LIMITS_ACTIONS_INVOKES_PERMINUTE": "{{ limits.invocationsPerMinute }}"
"LIMITS_ACTIONS_INVOKES_CONCURRENT": "{{ limits.concurrentInvocations }}"
"LIMITS_TRIGGERS_FIRES_PERMINUTE": "{{ limits.firesPerMinute }}"
"LIMITS_ACTIONS_SEQUENCE_MAXLENGTH": "{{ limits.sequenceMaxLength }}"
"CONFIG_whisk_memory_min": "{{ limit_action_memory_min | default() }}"
"CONFIG_whisk_memory_max": "{{ limit_action_memory_max | default() }}"
"CONFIG_whisk_memory_std": "{{ limit_action_memory_std | default() }}"
"CONFIG_whisk_timeLimit_min": "{{ limit_action_time_min | default() }}"
"CONFIG_whisk_timeLimit_max": "{{ limit_action_time_max | default() }}"
"CONFIG_whisk_timeLimit_std": "{{ limit_action_time_std | default() }}"
"CONFIG_whisk_concurrencyLimit_min": "{{ limit_action_concurrency_min | default() }}"
"CONFIG_whisk_concurrencyLimit_max": "{{ limit_action_concurrency_max | default() }}"
"CONFIG_whisk_concurrencyLimit_std": "{{ limit_action_concurrency_std | default() }}"
"CONFIG_whisk_featureFlags_requireApiKeyAnnotation": "{{ whisk.feature_flags.require_api_key_annotation | default(true) | lower }}"
"CONFIG_whisk_featureFlags_requireResponsePayload": "{{ whisk.feature_flags.require_response_payload | default(true) | lower }}"
"CONFIG_whisk_activation_payload_max":
"{{ limit_activation_payload | default() }}"
"RUNTIMES_MANIFEST": "{{ runtimesManifest | to_json }}"
"CONFIG_whisk_runtimes_defaultImagePrefix":
"{{ runtimes_default_image_prefix | default() }}"
"CONFIG_whisk_runtimes_defaultImageTag":
"{{ runtimes_default_image_tag | default() }}"
"CONFIG_whisk_runtimes_bypassPullForLocalImages":
"{{ runtimes_bypass_pull_for_local_images | default() | lower }}"
"CONFIG_whisk_runtimes_localImagePrefix":
"{{ runtimes_local_image_prefix | default() }}"
"METRICS_KAMON": "{{ metrics.kamon.enabled | default(false) | lower }}"
"METRICS_KAMON_TAGS": "{{ metrics.kamon.tags | default() | lower }}"
"METRICS_LOG": "{{ metrics.log.enabled | default(false) | lower }}"
"CONFIG_whisk_controller_protocol": "{{ controller.protocol }}"
"CONFIG_whisk_controller_https_keystorePath":
"/conf/{{ controller.ssl.keystore.name }}"
"CONFIG_whisk_controller_https_keystorePassword":
"{{ controller.ssl.keystore.password }}"
"CONFIG_whisk_controller_https_keystoreFlavor":
"{{ controller.ssl.storeFlavor }}"
"CONFIG_whisk_controller_https_clientAuth":
"{{ controller.ssl.clientAuth }}"
"CONFIG_whisk_loadbalancer_managedFraction":
"{{ controller.managedFraction }}"
"CONFIG_whisk_loadbalancer_blackboxFraction":
"{{ controller.blackboxFraction }}"
"CONFIG_whisk_loadbalancer_timeoutFactor":
"{{ controller.timeoutFactor }}"
"CONFIG_whisk_loadbalancer_timeoutAddon":
"{{ controller.timeoutAddon }}"
"CONFIG_kamon_statsd_hostname": "{{ metrics.kamon.host }}"
"CONFIG_kamon_statsd_port": "{{ metrics.kamon.port }}"
"CONFIG_whisk_spi_LogStoreProvider": "{{ userLogs.spi }}"
"CONFIG_whisk_spi_LoadBalancerProvider":
"{{ controller.loadbalancer.spi }}"
"CONFIG_whisk_spi_EntitlementSpiProvider": "{{ controller.entitlement.spi }}"
"CONFIG_whisk_spi_AuthenticationDirectiveProvider": "{{ controller.authentication.spi }}"
"CONFIG_logback_log_level": "{{ controller.loglevel }}"
"CONFIG_whisk_transactions_header": "{{ transactions.header }}"
"CONFIG_whisk_controller_activation_pollingFromDb": "{{ controller_activation_pollingFromDb | default(true) | lower }}"
- name: merge extra env variables
set_fact:
env: "{{ env | combine(controller.extraEnv) }}"
- name: setup elasticsearch activation store env
set_fact:
elastic_env:
"CONFIG_whisk_activationStore_elasticsearch_protocol": "{{ db.elasticsearch.protocol}}"
"CONFIG_whisk_activationStore_elasticsearch_hosts": "{{ elasticsearch_connect_string }}"
"CONFIG_whisk_activationStore_elasticsearch_indexPattern": "{{ db.elasticsearch.index_pattern }}"
"CONFIG_whisk_activationStore_elasticsearch_username": "{{ db.elasticsearch.auth.admin.username }}"
"CONFIG_whisk_activationStore_elasticsearch_password": "{{ db.elasticsearch.auth.admin.password }}"
"CONFIG_whisk_spi_ActivationStoreProvider": "org.apache.openwhisk.core.database.elasticsearch.ElasticSearchActivationStoreProvider"
when: db.activation_store.backend == "ElasticSearch"
- name: merge elasticsearch activation store env
set_fact:
env: "{{ env | combine(elastic_env) }}"
when: db.activation_store.backend == "ElasticSearch"
- name: populate volumes for controller
set_fact:
controller_volumes:
- "{{ whisk_logs_dir }}/{{ controller_name }}:/logs"
- "{{ controller.confdir }}/{{ controller_name }}:/conf"
- name: check if coverage collection is enabled
set_fact:
coverage_enabled: false
when: coverage_enabled is undefined
- name: ensure controller coverage directory is created with permissions
file:
path: "{{ coverage_logs_dir }}/controller/{{ item }}"
state: directory
mode: 0777
with_items:
- controller
- common
become: "{{ logs.dir.become }}"
when: coverage_enabled
- name: extend controller volume for coverage
set_fact:
controller_volumes: "{{ controller_volumes|default({}) + [coverage_logs_dir+'/controller:/coverage'] }}"
when: coverage_enabled
- name: include plugins
include_tasks: "{{ item }}.yml"
with_items: "{{ controller_plugins | default([]) }}"
when: not lean
- name: lean controller setup
include_tasks: "lean.yml"
when: lean
- name: (re)start controller
docker_container:
name: "{{ controller_name }}"
image:
"{{docker_registry~docker.image.prefix}}/controller:{{ 'cov' if (coverage_enabled) else docker.image.tag }}"
state: started
recreate: true
restart_policy: "{{ docker.restart.policy }}"
hostname: "{{ controller_name }}"
env: "{{ env }}"
volumes: "{{ controller_volumes }}"
ports: "{{ ports_to_expose }}"
# userns_mode, pid_mode and privileged required when controller running in lean mode
userns_mode: "{{ userns_mode | default('') }}"
pid_mode: "{{ pid_mode | default('') }}"
privileged: "{{ privileged | default('no') }}"
command:
/bin/sh -c
"exec /init.sh {{ controller_index }}
>> /logs/{{ controller_name }}_logs.log 2>&1"
- name: wait until the Controller in this host is up and running
uri:
url:
"{{controller.protocol}}://{{ansible_host}}:{{controller_port}}/ping"
validate_certs: "no"
client_key:
"{{ controller.confdir }}/{{ controller_name }}/{{ controller.ssl.key }}"
client_cert:
"{{ controller.confdir }}/{{ controller_name }}/{{ controller.ssl.cert }}"
register: result
until: result.status == 200
retries: 12
delay: 10