heat_template_version: wallaby description: > OpenStack containerized Neutron API service parameters: ContainerNeutronApiImage: description: image type: string tags: - role_specific ContainerNeutronConfigImage: description: The container image to use for the neutron config_volume type: string tags: - role_specific NeutronApiLoggingSource: type: json default: tag: openstack.neutron.api file: /var/log/containers/neutron/server.log 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 DeployIdentifier: default: '' type: string description: > Setting this to a unique value will re-run any deployment tasks which perform configuration on a Heat stack-update. EnableInternalTLS: type: boolean default: false NeutronApiOptVolumes: default: [] description: list of optional volumes to be mounted type: comma_delimited_list NeutronApiOptEnvVars: default: {} description: hash of optional environment variables type: json NeutronWorkers: default: '' description: | Sets the number of API workers for the Neutron service. The default value results in the configuration being left unset and a system-dependent default will be chosen (usually the number of processors). Please note that this can result in a large number of processes and memory consumption on systems with a large core count. On such systems it is recommended that a non-default value be selected that matches the load requirements. type: string NeutronRpcWorkers: default: '' description: | Sets the number of RPC workers for the Neutron service. If not specified, it'll take the value of NeutronWorkers and if this is not specified either, the default value results in the configuration being left unset and a system-dependent default will be chosen (usually 1). type: string NeutronPassword: description: The password for the neutron service and db account, used by neutron agents. type: string hidden: true NeutronAllowL3AgentFailover: default: 'True' description: Allow automatic l3-agent failover type: string NovaPassword: description: The password for the nova service and db account type: string hidden: true NeutronEnableDVR: description: Enable Neutron DVR. default: '' type: string NeutronEnableIgmpSnooping: description: Enable IGMP Snooping. type: boolean default: false KeystoneRegion: type: string default: 'regionOne' description: Keystone region for endpoint MonitoringSubscriptionNeutronServer: default: 'overcloud-neutron-server' type: string EnableSQLAlchemyCollectd: type: boolean description: > Set to true to enable the SQLAlchemy-collectd server plugin default: false NeutronApiPolicies: description: | A hash of policies to configure for Neutron API. e.g. { neutron-context_is_admin: { key: context_is_admin, value: 'role:admin' } } default: {} type: json NeutronOvsIntegrationBridge: default: '' type: string description: Name of Open vSwitch bridge to use NeutronPortQuota: default: '500' type: string description: Number of ports allowed per tenant, and minus means unlimited. NeutronSecurityGroupQuota: default: '10' type: string description: Number of security groups allowed per tenant, and minus means unlimited # TODO(bogdando): Right now OVN doesn't support AZ aware routing scheduling. # Later in Train cycle OVN ml2 driver will be extended to support it. # Until then, we have to determine if NeutronMechanismDrivers is OVN or OVS. NeutronMechanismDrivers: default: 'ovn' description: | The mechanism drivers for the Neutron tenant network. type: comma_delimited_list NeutronDefaultAvailabilityZones: description: Comma-separated list of default network availability zones to be used by Neutron if its resource is created without availability zone hints. If not set, no AZs will be configured for Neutron network services. default: [] type: comma_delimited_list NeutronNetworkSchedulerDriver: description: The network schedule driver to use for avialability zones. default: neutron.scheduler.dhcp_agent_scheduler.AZAwareWeightScheduler type: string NeutronRouterSchedulerDriver: description: The router schedule driver to use for avialability zones. default: neutron.scheduler.l3_agent_scheduler.AZLeastRoutersScheduler type: string NeutronDhcpLoadType: description: Additional to the availability zones aware network scheduler. default: networks type: string 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. CertificateKeySize: type: string default: '2048' description: Specifies the private key size used when creating the certificate. NeutronCertificateKeySize: type: string default: '' description: Override the private key size used when creating the certificate for this service MemcacheUseAdvancedPool: type: boolean description: | Use the advanced (eventlet safe) memcached client pool. default: true # DEPRECATED: the following options are deprecated and are currently maintained # for backwards compatibility. They will be removed in the Ocata cycle. NeutronL3HA: default: '' type: string description: | Whether to enable HA for virtual routers. When not set, L3 HA will be automatically enabled if the number of nodes hosting controller configurations and DVR is disabled. Valid values are 'true' or 'false' This parameter is being deprecated in Newton and is scheduled to be removed in Ocata. Future releases will enable L3 HA by default if it is appropriate for the deployment type. Alternate mechanisms will be available to override. NeutronAgentDownTime: default: 600 type: number description: | Seconds to regard the agent as down; should be at least twice NeutronGlobalReportInterval, to be sure the agent is down for good. EnforceSecureRbac: type: boolean default: false description: >- Setting this option to True will configure each OpenStack service to enforce Secure RBAC by setting `[oslo_policy] enforce_new_defaults` and `[oslo_policy] enforce_scope` to True. This introduces a consistent set of RBAC personas across OpenStack services that include support for system and project scope, as well as keystone's default roles, admin, member, and reader. Do not enable this functionality until all services in your deployment actually support secure RBAC. 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: - NeutronL3HA conditions: use_tls_proxy: {equals : [{get_param: EnableInternalTLS}, true]} neutron_workers_unset: {equals : [{get_param: NeutronWorkers}, '']} neutron_rpc_workers_unset: {equals : [{get_param: NeutronRpcWorkers}, '']} neutron_ovs_int_br_unset: {equals : [{get_param: NeutronOvsIntegrationBridge}, '']} internal_tls_enabled: {equals: [{get_param: EnableInternalTLS}, true]} neutron_dvr_unset: {equals : [{get_param: NeutronEnableDVR}, '']} is_ovn_in_neutron_mechanism_driver: {contains: ['ovn', {get_param: NeutronMechanismDrivers}]} az_unset: {equals: [{get_param: NeutronDefaultAvailabilityZones}, []]} ovn_and_tls: {and: [is_ovn_in_neutron_mechanism_driver, internal_tls_enabled]} enable_sqlalchemy_collectd: {equals : [{get_param: EnableSQLAlchemyCollectd}, true]} key_size_override_unset: {equals: [{get_param: NeutronCertificateKeySize}, '']} resources: TLSProxyBase: type: OS::TripleO::Services::TLSProxyBase properties: ServiceData: {get_param: ServiceData} ServiceNetMap: {get_param: ServiceNetMap} EndpointMap: {get_param: EndpointMap} RoleName: {get_param: RoleName} RoleParameters: {get_param: RoleParameters} EnableInternalTLS: {get_param: EnableInternalTLS} ContainersCommon: type: ../containers-common.yaml MySQLClient: type: ../database/mysql-client.yaml NeutronBase: type: ./neutron-base.yaml properties: EndpointMap: {get_param: EndpointMap} ServiceData: {get_param: ServiceData} ServiceNetMap: {get_param: ServiceNetMap} RoleName: {get_param: RoleName} RoleParameters: {get_param: RoleParameters} NeutronLogging: type: OS::TripleO::Services::Logging::NeutronApi properties: NeutronServiceName: server RoleParametersValue: type: OS::Heat::Value properties: type: json value: map_replace: - map_replace: - ContainerNeutronApiImage: ContainerNeutronApiImage ContainerNeutronConfigImage: ContainerNeutronConfigImage - values: {get_param: [RoleParameters]} - values: ContainerNeutronApiImage: {get_param: ContainerNeutronApiImage} ContainerNeutronConfigImage: {get_param: ContainerNeutronConfigImage} outputs: role_data: description: Role data for the Neutron API role. value: service_name: neutron_api firewall_rules: '114 neutron api': dport: - 9696 firewall_frontend_rules: '100 neutron_haproxy_frontend': dport: - 9696 firewall_ssl_frontend_rules: '100 neutron_haproxy_frontend_ssl': dport: - 13696 keystone_resources: neutron: endpoints: public: {get_param: [EndpointMap, NeutronPublic, uri]} internal: {get_param: [EndpointMap, NeutronInternal, uri]} admin: {get_param: [EndpointMap, NeutronAdmin, uri]} users: neutron: password: {get_param: NeutronPassword} region: {get_param: KeystoneRegion} service: 'network' monitoring_subscription: {get_param: MonitoringSubscriptionNeutronServer} config_settings: map_merge: - get_attr: [NeutronBase, role_data, config_settings] - get_attr: [TLSProxyBase, role_data, config_settings] - get_attr: [NeutronLogging, config_settings] - neutron::db::database_connection: make_url: scheme: {get_param: [EndpointMap, MysqlInternal, protocol]} username: neutron password: {get_param: NeutronPassword} host: {get_param: [EndpointMap, MysqlInternal, host]} path: /ovs_neutron query: if: - enable_sqlalchemy_collectd - read_default_file: /etc/my.cnf.d/tripleo.cnf read_default_group: tripleo plugin: collectd collectd_program_name: ovs_neutron collectd_host: localhost - read_default_file: /etc/my.cnf.d/tripleo.cnf read_default_group: tripleo neutron::policy::policies: {get_param: NeutronApiPolicies} - if: - {get_param: EnforceSecureRbac} - neutron::policy::enforce_scope: true neutron::policy::enforce_new_defaults: true neutron::keystone::authtoken::www_authenticate_uri: {get_param: [EndpointMap, KeystonePublic, uri_no_suffix] } neutron::keystone::authtoken::auth_url: {get_param: [EndpointMap, KeystoneInternal, uri_no_suffix]} neutron::server::agent_down_time: {get_param: NeutronAgentDownTime} neutron::server::allow_automatic_l3agent_failover: {get_param: NeutronAllowL3AgentFailover} neutron::server::enable_proxy_headers_parsing: true neutron::server::igmp_snooping_enable: {get_param: NeutronEnableIgmpSnooping} neutron::keystone::authtoken::password: {get_param: NeutronPassword} neutron::server::notifications::nova::auth_url: { get_param: [ EndpointMap, KeystoneInternal, uri_no_suffix ] } neutron::server::notifications::nova::project_name: 'service' neutron::server::notifications::nova::user_domain_name: 'Default' neutron::server::notifications::nova::project_domain_name: 'Default' neutron::server::notifications::nova::region_name: {get_param: KeystoneRegion} neutron::server::notifications::nova::password: {get_param: NovaPassword} neutron::server::notifications::nova::endpoint_type: 'internal' neutron::keystone::authtoken::project_name: 'service' neutron::keystone::authtoken::user_domain_name: 'Default' neutron::keystone::authtoken::project_domain_name: 'Default' neutron::keystone::authtoken::region_name: {get_param: KeystoneRegion} neutron::keystone::authtoken::interface: 'internal' neutron::keystone::authtoken::memcache_use_advanced_pool: {get_param: MemcacheUseAdvancedPool} neutron::quota::quota_port: {get_param: NeutronPortQuota} neutron::quota::quota_security_group: {get_param: NeutronSecurityGroupQuota} neutron::server::placement::password: {get_param: NovaPassword} neutron::server::placement::project_domain_name: 'Default' neutron::server::placement::project_name: 'service' neutron::server::placement::user_domain_name: 'Default' neutron::server::placement::username: nova neutron::server::placement::auth_url: {get_param: [EndpointMap, KeystoneInternal, uri_no_suffix]} neutron::server::placement::auth_type: 'password' neutron::server::placement::region_name: {get_param: KeystoneRegion} # NOTE: bind IP is found in hiera replacing the network name with the local node IP # for the given network; replacement examples (eg. for internal_api): # internal_api -> IP # internal_api_uri -> [IP] # internal_api_subnet - > IP/CIDR tripleo::profile::base::neutron::server::tls_proxy_bind_ip: str_replace: template: "%{hiera('$NETWORK')}" params: $NETWORK: {get_param: [ServiceNetMap, NeutronApiNetwork]} tripleo::profile::base::neutron::server::tls_proxy_fqdn: str_replace: template: "%{hiera('fqdn_$NETWORK')}" params: $NETWORK: {get_param: [ServiceNetMap, NeutronApiNetwork]} tripleo::profile::base::neutron::server::tls_proxy_port: get_param: [EndpointMap, NeutronInternal, port] # Bind to localhost if internal TLS is enabled, since we put a TLS # proxy in front. neutron::bind_host: if: - use_tls_proxy - "%{hiera('localhost_address')}" - str_replace: template: "%{hiera('$NETWORK')}" params: $NETWORK: {get_param: [ServiceNetMap, NeutronApiNetwork]} tripleo::profile::base::neutron::server::l3_ha_override: {get_param: NeutronL3HA} - if: - neutron_dvr_unset - {} - neutron::server::router_distributed: {get_param: NeutronEnableDVR} neutron::server::enable_dvr: {get_param: NeutronEnableDVR} - if: - neutron_workers_unset - {} - neutron::server::api_workers: {get_param: NeutronWorkers} - if: - neutron_rpc_workers_unset - if: - neutron_workers_unset - {} - neutron::server::rpc_workers: {get_param: NeutronWorkers} - neutron::server::rpc_workers: {get_param: NeutronRpcWorkers} - if: - neutron_ovs_int_br_unset - {} - neutron::server::ovs_integration_bridge: {get_param: NeutronOvsIntegrationBridge} - if: - az_unset - {} - neutron::server::dhcp_load_type: {get_param: NeutronDhcpLoadType} neutron::server::network_scheduler_driver: {get_param: NeutronNetworkSchedulerDriver} neutron::server::router_scheduler_driver: {get_param: NeutronRouterSchedulerDriver} neutron::server::default_availability_zones: {get_param: NeutronDefaultAvailabilityZones} - if: - ovn_and_tls - tripleo::profile::base::neutron::plugins::ml2::ovn::protocol: 'ssl' tripleo::profile::base::neutron::plugins::ml2::ovn::ovn_nb_private_key: '/etc/pki/tls/private/neutron_ovn.key' tripleo::profile::base::neutron::plugins::ml2::ovn::ovn_nb_certificate: '/etc/pki/tls/certs/neutron_ovn.crt' tripleo::profile::base::neutron::plugins::ml2::ovn::ovn_sb_private_key: '/etc/pki/tls/private/neutron_ovn.key' tripleo::profile::base::neutron::plugins::ml2::ovn::ovn_sb_certificate: '/etc/pki/tls/certs/neutron_ovn.crt' tripleo::profile::base::neutron::plugins::ml2::ovn::ovn_nb_ca_cert: {get_param: InternalTLSCAFile} tripleo::profile::base::neutron::plugins::ml2::ovn::ovn_sb_ca_cert: {get_param: InternalTLSCAFile} - {} service_config_settings: rsyslog: tripleo_logging_sources_neutron_api: - {get_param: NeutronApiLoggingSource} mysql: neutron::db::mysql::password: {get_param: NeutronPassword} neutron::db::mysql::user: neutron neutron::db::mysql::host: '%' neutron::db::mysql::dbname: ovs_neutron # BEGIN DOCKER SETTINGS puppet_config: config_volume: neutron puppet_tags: neutron_config,neutron_api_paste_ini step_config: list_join: - "\n" - - include tripleo::profile::base::neutron::server - {get_attr: [MySQLClient, role_data, step_config]} config_image: {get_attr: [RoleParametersValue, value, ContainerNeutronConfigImage]} kolla_config: /var/lib/kolla/config_files/neutron_api.json: command: list_join: - ' ' - - /usr/bin/neutron-server --config-file /usr/share/neutron/neutron-dist.conf --config-dir /usr/share/neutron/server --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugin.ini --config-dir /etc/neutron/conf.d/common --config-dir /etc/neutron/conf.d/neutron-server - get_attr: [NeutronLogging, cmd_extra_args] config_files: &neutron_api_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 optional: true preserve_properties: true permissions: &neutron_api_permissions - path: /var/log/neutron owner: neutron:neutron recurse: true - path: /etc/pki/tls/certs/neutron_ovn.crt owner: neutron:neutron optional: true perm: '0644' - path: /etc/pki/tls/private/neutron_ovn.key owner: neutron:neutron optional: true perm: '0644' /var/lib/kolla/config_files/neutron_api_db_sync.json: command: "/usr/bin/bootstrap_host_exec neutron_api neutron-db-manage upgrade heads" # FIXME: we should make config file permissions right # and run as neutron user #command: "/usr/bin/bootstrap_host_exec neutron_api su neutron -s /bin/bash -c 'neutron-db-manage upgrade heads'" config_files: *neutron_api_config_files permissions: *neutron_api_permissions /var/lib/kolla/config_files/neutron_server_tls_proxy.json: command: /usr/sbin/httpd -DFOREGROUND config_files: - source: "/var/lib/kolla/config_files/src/*" dest: "/" merge: true preserve_properties: true - source: "/var/lib/kolla/config_files/src/etc/httpd/conf.d" dest: "/etc/httpd/conf.d" merge: false preserve_properties: true - source: "/var/lib/kolla/config_files/src/etc/httpd/conf.modules.d" dest: "/etc/httpd/conf.modules.d" merge: false preserve_properties: true docker_config: step_2: get_attr: [NeutronLogging, docker_config, step_2] step_3: neutron_db_sync: image: &neutron_api_image {get_attr: [RoleParametersValue, value, ContainerNeutronApiImage]} cap_add: - AUDIT_WRITE net: host privileged: false detach: false user: root volumes: list_concat: - {get_attr: [ContainersCommon, volumes]} - {get_attr: [NeutronLogging, volumes]} - {get_param: NeutronApiOptVolumes} - - /var/lib/kolla/config_files/neutron_api_db_sync.json:/var/lib/kolla/config_files/config.json:ro - /var/lib/config-data/puppet-generated/neutron:/var/lib/kolla/config_files/src:ro environment: KOLLA_CONFIG_STRATEGY: COPY_ALWAYS TRIPLEO_DEPLOY_IDENTIFIER: {get_param: DeployIdentifier} step_4: map_merge: - neutron_api: start_order: 0 image: *neutron_api_image net: host privileged: false restart: always healthcheck: test: /openstack/healthcheck volumes: list_concat: - {get_attr: [ContainersCommon, volumes]} - {get_attr: [NeutronLogging, volumes]} - {get_param: NeutronApiOptVolumes} - - /var/lib/kolla/config_files/neutron_api.json:/var/lib/kolla/config_files/config.json:ro - /var/lib/config-data/puppet-generated/neutron:/var/lib/kolla/config_files/src:ro - if: - ovn_and_tls - - /etc/pki/tls/certs/neutron_ovn.crt:/var/lib/kolla/config_files/src-tls/etc/pki/tls/certs/neutron_ovn.crt:ro - /etc/pki/tls/private/neutron_ovn.key:/var/lib/kolla/config_files/src-tls/etc/pki/tls/private/neutron_ovn.key:ro - null environment: map_merge: - {get_param: NeutronApiOptEnvVars} - KOLLA_CONFIG_STRATEGY: COPY_ALWAYS - if: - internal_tls_enabled - neutron_server_tls_proxy: image: *neutron_api_image net: host user: root restart: always volumes: list_concat: - {get_attr: [ContainersCommon, volumes]} - {get_attr: [NeutronLogging, volumes]} - - /var/lib/kolla/config_files/neutron_server_tls_proxy.json:/var/lib/kolla/config_files/config.json:ro - /var/lib/config-data/puppet-generated/neutron:/var/lib/kolla/config_files/src:ro - /etc/pki/tls/certs/httpd:/etc/pki/tls/certs/httpd:ro - /etc/pki/tls/private/httpd:/etc/pki/tls/private/httpd:ro environment: KOLLA_CONFIG_STRATEGY: COPY_ALWAYS - {} host_prep_tasks: {get_attr: [NeutronLogging, host_prep_tasks]} metadata_settings: list_concat: - {get_attr: [TLSProxyBase, role_data, metadata_settings]} - if: - ovn_and_tls - - service: neutron_ovn network: {get_param: [ServiceNetMap, NeutronApiNetwork]} type: node - null deploy_steps_tasks: if: - ovn_and_tls - - name: Certificate generation when: step|int == 1 block: - include_role: name: linux-system-roles.certificate vars: certificate_requests: - name: neutron_ovn dns: str_replace: template: "{{fqdn_$NETWORK}}" params: $NETWORK: {get_param: [ServiceNetMap, NeutronApiNetwork]} principal: str_replace: template: "neutron_ovn/{{fqdn_$NETWORK}}@{{idm_realm}}" params: $NETWORK: {get_param: [ServiceNetMap, NeutronApiNetwork]} key_size: if: - key_size_override_unset - {get_param: CertificateKeySize} - {get_param: NeutronCertificateKeySize} ca: ipa - null external_upgrade_tasks: - when: - step|int == 1 tags: - never - system_upgrade_transfer_data - system_upgrade_stop_services block: - name: Stop neutron api container import_role: name: tripleo_container_stop vars: tripleo_containers_to_stop: - neutron_api tripleo_delegate_to: "{{ groups['neutron_api'] | difference(groups['excluded_overcloud']) }}" external_update_tasks: - name: Check if python3-openvswitch3.1 workaround is needed delegate_to: "{{groups['neutron_api'][0]}}" become: true tags: - ovn - ovn_image when: step|int == 1 shell: | podman exec neutron_api rpm -q python3-openvswitch3.1 register: neutron_python_ovs_3_1 failed_when: false - name: Update neutron_api first everywhere become: true tags: - ovn - ovn_image when: - step|int == 1 - neutron_python_ovs_3_1.rc == 0 block: - name: Move virtual IPs to another node before stopping pacemaker delegate_to: "{{groups['neutron_api'][0]}}" when: - hostvars[groups['neutron_api'][0]]["haproxy_node_names"]|default([])|length > 1 shell: | CLUSTER_NODE=$(crm_node -n) echo "Retrieving all the VIPs which are hosted on this node" VIPS_TO_MOVE=$(crm_mon --as-xml | xmllint --xpath '//resource[@resource_agent="ocf:heartbeat:IPaddr2" and @role = "Started" and @managed = "true" and ./node[@name = "'${CLUSTER_NODE}'"]]/@id' - | sed -e 's/id=//g' -e 's/"//g') for v in ${VIPS_TO_MOVE}; do echo "Moving VIP $v on another node" pcs resource ban $v ${CLUSTER_NODE} --wait=300 done echo "Removing the location constraints that were created to move the VIPs" for v in ${VIPS_TO_MOVE}; do echo "Removing location ban for VIP $v" ban_id=$(cibadmin --query | xmllint --xpath 'string(//rsc_location[@rsc="'${v}'" and @node="'${CLUSTER_NODE}'" and @score="-INFINITY"]/@id)' -) if [ -n "$ban_id" ]; then pcs constraint remove ${ban_id} else echo "Could not retrieve and clear location constraint for VIP $v" 2>&1 fi done - name: Create firewall nat prerouting and postrouting delegate_to: "{{groups['neutron_api'][0]}}" shell: | set -o pipefail LOCAL_BACKEND=$(grep {{groups['neutron_api'][0]}} /var/lib/config-data/puppet-generated/haproxy/etc/haproxy/haproxy.cfg | \ grep ":9696 " | awk '{print $3}') IP=${LOCAL_BACKEND%:*} if [[ $IP =~ .*:.* ]] then PROTOCOL="ip6" # we need to temporarly allow ipv6 forwarding, this will get reset by deployment run sysctl -w net.ipv6.conf.all.forwarding=1 else PROTOCOL="ip" fi nft add table $PROTOCOL nat nft -- add chain $PROTOCOL nat prerouting { type nat hook prerouting priority -100 \; } nft add chain $PROTOCOL nat postrouting { type nat hook postrouting priority 100 \; } - name: Redirect neutron backend traffic for 60s to other host delegate_to: "{{groups['neutron_api'][0]}}" shell: | set -o pipefail source /etc/os-release; test "${VERSION_ID%*}" = "9.0" && exit 0 LOCAL_BACKEND=$(grep {{groups['neutron_api'][0]}} /var/lib/config-data/puppet-generated/haproxy/etc/haproxy/haproxy.cfg | \ grep ":9696 " | awk '{print $3}') REMOTE_BACKEND=$(grep ":9696 " /var/lib/config-data/puppet-generated/haproxy/etc/haproxy/haproxy.cfg | \ grep server | grep -v {{groups['neutron_api'][0]}} | head -n1 | awk '{print $3}') IP=${LOCAL_BACKEND%:*} PORT=9696 if [[ $IP =~ .*:.* ]] then PROTOCOL="ip6" else PROTOCOL="ip" fi REMOTE_IP=${REMOTE_BACKEND%:*} nft add rule $PROTOCOL nat postrouting $PROTOCOL daddr $REMOTE_IP tcp dport 9696 counter meta time $(date +%s)-$(date -d'+60 seconds' +%s) masquerade comment neutron_api nft add rule $PROTOCOL nat prerouting $PROTOCOL daddr $IP tcp dport 9696 counter meta time $(date +%s)-$(date -d'+60 seconds' +%s) dnat to $REMOTE_IP comment neutron_api - name: Insanity neutron update first delegate_to: "{{groups['neutron_api'][0]}}" become: true tripleo_container_manage: config_dir: "/var/lib/tripleo-config/container-startup-config/step_4" config_id: - 'neutron_api' config_patterns: "*neutron_api.json" config_overrides: ".*neutron_api": image: {get_attr: [RoleParametersValue, value, ContainerNeutronApiImage]} name: "neutron_api" - wait_for: timeout: 50 - name: Delete redirect rules delegate_to: "{{groups['neutron_api'][0]}}" shell: | set -o pipefail LOCAL_BACKEND=$(grep {{groups['neutron_api'][0]}} /var/lib/config-data/puppet-generated/haproxy/etc/haproxy/haproxy.cfg | \ grep ":9696 " | awk '{print $3}') IP=${LOCAL_BACKEND%:*} if [[ $IP =~ .*:.* ]] then PROTOCOL="ip6" else PROTOCOL="ip" fi nft -a list chain $PROTOCOL nat postrouting | grep neutron_api | awk -F# '{print "nat postrouting "$2}' | \ while read i; do bash -c "nft delete rule $PROTOCOL $i"; done nft -a list chain $PROTOCOL nat prerouting | grep neutron_api | awk -F# '{print "nat prerouting "$2}' | \ while read i; do bash -c "nft delete rule $PROTOCOL $i"; done - name: Move virtual IPs to another node before stopping pacemaker delegate_to: "{{groups['neutron_api'][1]}}" when: - hostvars[groups['neutron_api'][1]]["haproxy_node_names"]|default([])|length > 1 - groups['neutron_api'] | default([]) | length > 1 shell: | CLUSTER_NODE=$(crm_node -n) echo "Retrieving all the VIPs which are hosted on this node" VIPS_TO_MOVE=$(crm_mon --as-xml | xmllint --xpath '//resource[@resource_agent="ocf:heartbeat:IPaddr2" and @role = "Started" and @managed = "true" and ./node[@name = "'${CLUSTER_NODE}'"]]/@id' - | sed -e 's/id=//g' -e 's/"//g') for v in ${VIPS_TO_MOVE}; do echo "Moving VIP $v on another node" pcs resource ban $v ${CLUSTER_NODE} --wait=300 done echo "Removing the location constraints that were created to move the VIPs" for v in ${VIPS_TO_MOVE}; do echo "Removing location ban for VIP $v" ban_id=$(cibadmin --query | xmllint --xpath 'string(//rsc_location[@rsc="'${v}'" and @node="'${CLUSTER_NODE}'" and @score="-INFINITY"]/@id)' -) if [ -n "$ban_id" ]; then pcs constraint remove ${ban_id} else echo "Could not retrieve and clear location constraint for VIP $v" 2>&1 fi done - name: Create firewall nat prerouting and postrouting delegate_to: "{{groups['neutron_api'][1]}}" when: - groups['neutron_api'] | default([]) | length > 1 shell: | set -o pipefail LOCAL_BACKEND=$(grep {{groups['neutron_api'][1]}} /var/lib/config-data/puppet-generated/haproxy/etc/haproxy/haproxy.cfg | \ grep ":9696 " | awk '{print $3}') IP=${LOCAL_BACKEND%:*} if [[ $IP =~ .*:.* ]] then PROTOCOL="ip6" # we need to temporarly allow ipv6 forwarding, this will get reset by deployment run sysctl -w net.ipv6.conf.all.forwarding=1 else PROTOCOL="ip" fi nft add table $PROTOCOL nat nft -- add chain $PROTOCOL nat prerouting { type nat hook prerouting priority -100 \; } nft add chain $PROTOCOL nat postrouting { type nat hook postrouting priority 100 \; } - name: Redirect neutron backend traffic for 60s to other host delegate_to: "{{groups['neutron_api'][1]}}" when: - groups['neutron_api'] | default([]) | length > 1 shell: | set -o pipefail source /etc/os-release; test "${VERSION_ID%*}" = "9.0" && exit 0 LOCAL_BACKEND=$(grep {{groups['neutron_api'][1]}} /var/lib/config-data/puppet-generated/haproxy/etc/haproxy/haproxy.cfg | \ grep ":9696 " | awk '{print $3}') REMOTE_BACKEND=$(grep ":9696 " /var/lib/config-data/puppet-generated/haproxy/etc/haproxy/haproxy.cfg | \ grep server | grep -v {{groups['neutron_api'][1]}} | head -n1 | awk '{print $3}') IP=${LOCAL_BACKEND%:*} PORT=9696 if [[ $IP =~ .*:.* ]] then PROTOCOL="ip6" else PROTOCOL="ip" fi REMOTE_IP=${REMOTE_BACKEND%:*} nft add rule $PROTOCOL nat postrouting $PROTOCOL daddr $REMOTE_IP tcp dport 9696 counter meta time $(date +%s)-$(date -d'+60 seconds' +%s) masquerade comment neutron_api nft add rule $PROTOCOL nat prerouting $PROTOCOL daddr $IP tcp dport 9696 counter meta time $(date +%s)-$(date -d'+60 seconds' +%s) dnat to $REMOTE_IP comment neutron_api - name: Insanity neutron update first delegate_to: "{{groups['neutron_api'][1]}}" become: true tripleo_container_manage: config_dir: "/var/lib/tripleo-config/container-startup-config/step_4" config_id: - 'neutron_api' config_patterns: "*neutron_api.json" config_overrides: ".*neutron_api": image: {get_attr: [RoleParametersValue, value, ContainerNeutronApiImage]} name: "neutron_api" when: - groups['neutron_api'] | default([]) | length > 1 - wait_for: timeout: 50 when: - groups['neutron_api'] | default([]) | length > 1 - name: Delete redirect rules delegate_to: "{{groups['neutron_api'][1]}}" when: - groups['neutron_api'] | default([]) | length > 1 shell: | set -o pipefail LOCAL_BACKEND=$(grep {{groups['neutron_api'][1]}} /var/lib/config-data/puppet-generated/haproxy/etc/haproxy/haproxy.cfg | \ grep ":9696 " | awk '{print $3}') IP=${LOCAL_BACKEND%:*} if [[ $IP =~ .*:.* ]] then PROTOCOL="ip6" else PROTOCOL="ip" fi nft -a list chain $PROTOCOL nat postrouting | grep neutron_api | awk -F# '{print "nat postrouting "$2}' | \ while read i; do bash -c "nft delete rule $PROTOCOL $i"; done nft -a list chain $PROTOCOL nat prerouting | grep neutron_api | awk -F# '{print "nat prerouting "$2}' | \ while read i; do bash -c "nft delete rule $PROTOCOL $i"; done - name: Move virtual IPs to another node before stopping pacemaker delegate_to: "{{groups['neutron_api'][2]}}" when: - hostvars[groups['neutron_api'][2]]["haproxy_node_names"]|default([])|length > 1 - groups['neutron_api'] | default([]) | length > 2 shell: | CLUSTER_NODE=$(crm_node -n) echo "Retrieving all the VIPs which are hosted on this node" VIPS_TO_MOVE=$(crm_mon --as-xml | xmllint --xpath '//resource[@resource_agent="ocf:heartbeat:IPaddr2" and @role = "Started" and @managed = "true" and ./node[@name = "'${CLUSTER_NODE}'"]]/@id' - | sed -e 's/id=//g' -e 's/"//g') for v in ${VIPS_TO_MOVE}; do echo "Moving VIP $v on another node" pcs resource ban $v ${CLUSTER_NODE} --wait=300 done echo "Removing the location constraints that were created to move the VIPs" for v in ${VIPS_TO_MOVE}; do echo "Removing location ban for VIP $v" ban_id=$(cibadmin --query | xmllint --xpath 'string(//rsc_location[@rsc="'${v}'" and @node="'${CLUSTER_NODE}'" and @score="-INFINITY"]/@id)' -) if [ -n "$ban_id" ]; then pcs constraint remove ${ban_id} else echo "Could not retrieve and clear location constraint for VIP $v" 2>&1 fi done - name: Create firewall nat prerouting and postrouting delegate_to: "{{groups['neutron_api'][2]}}" when: - groups['neutron_api'] | default([]) | length > 2 shell: | set -o pipefail LOCAL_BACKEND=$(grep {{groups['neutron_api'][2]}} /var/lib/config-data/puppet-generated/haproxy/etc/haproxy/haproxy.cfg | \ grep ":9696 " | awk '{print $3}') IP=${LOCAL_BACKEND%:*} if [[ $IP =~ .*:.* ]] then PROTOCOL="ip6" # we need to temporarly allow ipv6 forwarding, this will get reset by deployment run sysctl -w net.ipv6.conf.all.forwarding=1 else PROTOCOL="ip" fi nft add table $PROTOCOL nat nft -- add chain $PROTOCOL nat prerouting { type nat hook prerouting priority -100 \; } nft add chain $PROTOCOL nat postrouting { type nat hook postrouting priority 100 \; } - name: Redirect neutron backend traffic for 60s to other host delegate_to: "{{groups['neutron_api'][2]}}" when: - groups['neutron_api'] | default([]) | length > 2 shell: | set -o pipefail source /etc/os-release; test "${VERSION_ID%*}" = "9.0" && exit 0 LOCAL_BACKEND=$(grep {{groups['neutron_api'][2]}} /var/lib/config-data/puppet-generated/haproxy/etc/haproxy/haproxy.cfg | \ grep ":9696 " | awk '{print $3}') REMOTE_BACKEND=$(grep ":9696 " /var/lib/config-data/puppet-generated/haproxy/etc/haproxy/haproxy.cfg | \ grep server | grep -v {{groups['neutron_api'][2]}} | head -n1 | awk '{print $3}') IP=${LOCAL_BACKEND%:*} PORT=9696 if [[ $IP =~ .*:.* ]] then PROTOCOL="ip6" else PROTOCOL="ip" fi REMOTE_IP=${REMOTE_BACKEND%:*} nft add rule $PROTOCOL nat postrouting $PROTOCOL daddr $REMOTE_IP tcp dport 9696 counter meta time $(date +%s)-$(date -d'+60 seconds' +%s) masquerade comment neutron_api nft add rule $PROTOCOL nat prerouting $PROTOCOL daddr $IP tcp dport 9696 counter meta time $(date +%s)-$(date -d'+60 seconds' +%s) dnat to $REMOTE_IP comment neutron_api - name: Insanity neutron update first delegate_to: "{{groups['neutron_api'][2]}}" become: true tripleo_container_manage: config_dir: "/var/lib/tripleo-config/container-startup-config/step_4" config_id: - 'neutron_api' config_patterns: "*neutron_api.json" config_overrides: ".*neutron_api": image: {get_attr: [RoleParametersValue, value, ContainerNeutronApiImage]} name: "neutron_api" when: - groups['neutron_api'] | default([]) | length > 2 - wait_for: timeout: 50 when: - groups['neutron_api'] | default([]) | length > 2 - name: Delete redirect rules delegate_to: "{{groups['neutron_api'][2]}}" shell: | set -o pipefail LOCAL_BACKEND=$(grep {{groups['neutron_api'][2]}} /var/lib/config-data/puppet-generated/haproxy/etc/haproxy/haproxy.cfg | \ grep ":9696 " | awk '{print $3}') IP=${LOCAL_BACKEND%:*} if [[ $IP =~ .*:.* ]] then PROTOCOL="ip6" else PROTOCOL="ip" fi nft -a list chain $PROTOCOL nat postrouting | grep neutron_api | awk -F# '{print "nat postrouting "$2}' | \ while read i; do bash -c "nft delete rule $PROTOCOL $i"; done nft -a list chain $PROTOCOL nat prerouting | grep neutron_api | awk -F# '{print "nat prerouting "$2}' | \ while read i; do bash -c "nft delete rule $PROTOCOL $i"; done when: - groups['neutron_api'] | default([]) | length > 2