heat_template_version: wallaby description: > Containerized etcd services parameters: ContainerEtcdImage: description: image type: string tags: - role_specific ContainerEtcdConfigImage: description: The container image to use for the etcd config_volume type: string tags: - role_specific EndpointMap: default: {} description: Mapping of service endpoint -> protocol. Typically set via parameter_defaults in the resource registry. type: json ServiceData: default: {} description: Dictionary packing service data type: json ServiceNetMap: default: {} description: Mapping of service_name -> network name. Typically set via parameter_defaults in the resource registry. Use parameter_merge_strategies to merge it with the defaults. type: json RoleName: default: '' description: Role name on which the service is applied type: string RoleParameters: default: {} description: Parameters specific to the role type: json EtcdInitialClusterToken: description: Initial cluster token for the etcd cluster during bootstrap. type: string hidden: true EtcdInitialClusterState: description: Initial cluster state ("new" or "existing"). The default value "new" needs to be overridden only when an overcloud node is replaced, at which time the value should be set to "existing". type: string default: 'new' constraints: - allowed_values: ['new', 'existing'] MonitoringSubscriptionEtcd: default: 'overcloud-etcd' type: string EnableInternalTLS: type: boolean default: false EnableEtcdInternalTLS: description: Controls whether etcd and the cinder-volume service use TLS for cinder's lock manager, even when the rest of the internal API network is using TLS. type: boolean default: true InternalTLSCAFile: default: '/etc/ipa/ca.crt' type: string description: Specifies the default CA cert to use if TLS is used for services in the internal network. Debug: default: false description: Set to True to enable debugging on all services. type: boolean CertificateKeySize: type: string default: '2048' description: Specifies the private key size used when creating the certificate. EtcdCertificateKeySize: type: string default: '' description: Override the private key size used when creating the certificate for this service parameter_groups: - label: deprecated description: | The following parameters are deprecated and will be removed. They should not be relied on for new deployments. If you have concerns regarding deprecated parameters, please contact the TripleO development team on IRC or the OpenStack mailing list. parameters: - EnableEtcdInternalTLS conditions: internal_tls_enabled: and: - {get_param: EnableInternalTLS} - {get_param: EnableEtcdInternalTLS} key_size_override_set: not: {equals: [{get_param: EtcdCertificateKeySize}, '']} resources: ContainersCommon: type: ../containers-common.yaml RoleParametersValue: type: OS::Heat::Value properties: type: json value: map_replace: - map_replace: - ContainerEtcdImage: ContainerEtcdImage ContainerEtcdConfigImage: ContainerEtcdConfigImage - values: {get_param: [RoleParameters]} - values: ContainerEtcdImage: {get_param: ContainerEtcdImage} ContainerEtcdConfigImage: {get_param: ContainerEtcdConfigImage} outputs: role_data: description: Role data for the etcd role. value: service_name: etcd firewall_rules: '141 etcd': dport: - 2379 - 2380 firewall_frontend_rules: '100 ectd_haproxy_frontend': dport: - 2379 monitoring_subscription: {get_param: MonitoringSubscriptionEtcd} config_settings: map_merge: - etcd::etcd_name: str_replace: template: "%{lookup('fqdn_$NETWORK')}" params: $NETWORK: {get_param: [ServiceNetMap, EtcdNetwork]} tripleo::profile::base::etcd::bind_ip: str_replace: template: "%{lookup('$NETWORK')}" params: $NETWORK: {get_param: [ServiceNetMap, EtcdNetwork]} tripleo::profile::base::etcd::client_port: '2379' tripleo::profile::base::etcd::peer_port: '2380' etcd::debug: {get_param: Debug} etcd::initial_cluster_token: {get_param: EtcdInitialClusterToken} etcd::initial_cluster_state: {get_param: EtcdInitialClusterState} etcd::manage_package: false etcd::manage_service: false - if: - internal_tls_enabled - tripleo::profile::base::etcd::certificate_specs: service_certificate: '/etc/pki/tls/certs/etcd.crt' service_key: '/etc/pki/tls/private/etcd.key' etcd::trusted_ca_file: {get_param: InternalTLSCAFile} etcd::peer_trusted_ca_file: {get_param: InternalTLSCAFile} # Ensure etcd and cinder-volume aren't configured to use TLS - tripleo::profile::base::etcd::enable_internal_tls: false tripleo::profile::base::cinder::volume::enable_internal_tls: false # BEGIN DOCKER SETTINGS puppet_config: config_volume: etcd config_image: &etcd_config_image {get_attr: [RoleParametersValue, value, ContainerEtcdConfigImage]} step_config: list_join: - "\n" - - "['Etcd_key'].each |String $val| { noop_resource($val) }" - "include tripleo::profile::base::etcd" kolla_config: /var/lib/kolla/config_files/etcd.json: command: /usr/bin/etcd --config-file /etc/etcd/etcd.yml config_files: - source: "/var/lib/kolla/config_files/src/*" dest: "/" merge: true preserve_properties: true - source: "/var/lib/kolla/config_files/src-tls/*" dest: "/" merge: true preserve_properties: true optional: true permissions: - path: /var/lib/etcd owner: etcd:etcd recurse: true - path: /etc/pki/tls/certs/etcd.crt owner: etcd:etcd - path: /etc/pki/tls/private/etcd.key owner: etcd:etcd container_config_scripts: etcd_update_members.sh: mode: "0700" content: str_replace: template: | #!/bin/bash echo "####################################" echo "### $(date -u) ###" source /etc/etcd/etcd.conf export ETCDCTL_API=3 ETCDCTL="etcdctl TLS_OPTS --endpoints=${ETCD_LISTEN_CLIENT_URLS}" # Ask etcd for the current list of members eval $ETCDCTL member list | tr -d "," > /tmp/etcd-members # etcdctl doesn't generate reliable error status, so use presence of the # node's own name to determine whether this node is capable of managing # etcd membership. ETCD_NAME=$(hiera -c /etc/puppet/hiera.yaml etcd::etcd_name) if ! grep -q $ETCD_NAME /tmp/etcd-members; then echo "This is a new node that is unable to manage etcd membership" exit 0 fi # Remove old members. These are nodes in the current list of members # that are *not* in the ETCD_INITIAL_CLUSTER. while read id status name peers clients; do \ if [[ "${ETCD_INITIAL_CLUSTER}" != *"${name}=${peers}"* ]]; then echo "Removing old member ${name} (ID ${id}) from the cluster" eval $ETCDCTL member remove ${id} fi done < /tmp/etcd-members # Add new members. These are nodes in the ETCD_INITIAL_CLUSTER that are # not in the list of current members. ETCD_INITIAL_CLUSTER is a comma # delimited list of "name=peers" tuples, so iterate over the list. IFS=, ETCD_MEMBERS=(${ETCD_INITIAL_CLUSTER}) for member in ${ETCD_MEMBERS[@]}; do \ # Split the tuple IFS='=' read name peers <<< $member if ! grep -q "${name} ${peers}" /tmp/etcd-members; then echo "Adding new member ${name} to the cluster" eval $ETCDCTL member add ${name} --peer-urls=${peers} fi done params: TLS_OPTS: if: - internal_tls_enabled - str_replace: template: "--cacert=TLS_CA --cert=/etc/pki/tls/certs/etcd.crt --key=/etc/pki/tls/private/etcd.key" params: TLS_CA: {get_param: InternalTLSCAFile} - "" docker_config: step_2: etcd: image: {get_attr: [RoleParametersValue, value, ContainerEtcdImage]} net: host privileged: false restart: always healthcheck: test: /openstack/healthcheck volumes: list_concat: - {get_attr: [ContainersCommon, volumes]} - - /var/lib/etcd:/var/lib/etcd - /var/lib/kolla/config_files/etcd.json:/var/lib/kolla/config_files/config.json:ro - /var/lib/config-data/puppet-generated/etcd:/var/lib/kolla/config_files/src:ro - /var/lib/container-config-scripts/etcd_update_members.sh:/etcd_update_members.sh:ro - if: - internal_tls_enabled - - /etc/pki/tls/certs/etcd.crt:/var/lib/kolla/config_files/src-tls/etc/pki/tls/certs/etcd.crt:ro - /etc/pki/tls/private/etcd.key:/var/lib/kolla/config_files/src-tls/etc/pki/tls/private/etcd.key:ro environment: KOLLA_CONFIG_STRATEGY: COPY_ALWAYS container_puppet_tasks: # Etcd keys initialization occurs only on single node step_2: config_volume: 'etcd_init_tasks' puppet_tags: 'etcd_key' step_config: | include tripleo::profile::base::etcd config_image: *etcd_config_image # TODO(mwhahaha): need to check if this works correctly or we need to switch to a bootstrap execution volumes: - /var/lib/config-data/puppet-generated/etcd/etc/etcd:/etc/etcd:ro - /var/lib/etcd:/var/lib/etcd:ro deploy_steps_tasks: list_concat: - - name: Manage etcd cluster membership vars: initial_cluster_state: {get_param: EtcdInitialClusterState} shell: | "{{ container_cli }}" exec -ti -u root etcd /etcd_update_members.sh 2>&1 | \ tee -a /var/log/containers/stdouts/etcd_update_members.log become: true failed_when: false when: - step|int == 3 - initial_cluster_state == "existing" - if: - internal_tls_enabled - - name: Certificate generation when: step|int == 1 block: - include_role: name: linux-system-roles.certificate vars: certificate_requests: - name: etcd dns: - str_replace: template: "{{fqdn_$NETWORK}}" params: $NETWORK: {get_param: [ServiceNetMap, EtcdNetwork]} - str_replace: template: "{{cloud_names.cloud_name_NETWORK}}" params: NETWORK: {get_param: [ServiceNetMap, EtcdNetwork]} # etcd3 expects to use IP addresses, so add a SAN IP to its cert ip: str_replace: template: "{{NETWORK_ip}}" params: NETWORK: {get_param: [ServiceNetMap, EtcdNetwork]} principal: str_replace: template: "etcd/{{fqdn_$NETWORK}}@{{idm_realm}}" params: $NETWORK: {get_param: [ServiceNetMap, EtcdNetwork]} run_after: | # cinder uses etcd, so its containers also need to be refreshed container_names=$({{container_cli}} ps --format=\{\{.Names\}\} | grep -E 'cinder|etcd') service_crt="/etc/pki/tls/certs/etcd.crt" service_key="/etc/pki/tls/private/etcd.key" kolla_dir="/var/lib/kolla/config_files/src-tls" # For each container, check whether the cert file needs to be updated. # The check is necessary because the original THT design directly bind mounted # the files to their final location, and did not copy them in via $kolla_dir. # Regardless of whether the container is directly using the files, or a copy, # there's no need to trigger a reload because the cert is not cached. for container_name in ${container_names[*]}; do {{container_cli}} exec -u root "$container_name" bash -c " [[ -f ${kolla_dir}/${service_crt} ]] && cp ${kolla_dir}/${service_crt} $service_crt; [[ -f ${kolla_dir}/${service_key} ]] && cp ${kolla_dir}/${service_key} $service_key; true " done key_size: if: - key_size_override_set - {get_param: EtcdCertificateKeySize} - {get_param: CertificateKeySize} ca: ipa host_prep_tasks: - name: create /var/lib/etcd file: path: /var/lib/etcd state: directory setype: container_file_t external_deploy_tasks: if: - internal_tls_enabled - - name: check if ipa server has required permissions when: step|int == 1 import_role: name: tls_everywhere tasks_from: ipa-server-check upgrade_tasks: [] metadata_settings: if: - internal_tls_enabled - - service: etcd network: {get_param: [ServiceNetMap, EtcdNetwork]} type: vip - service: etcd network: {get_param: [ServiceNetMap, EtcdNetwork]} type: node