Merge "Move Neutron to uWSGI."

This commit is contained in:
Zuul 2024-05-10 21:47:43 +00:00 committed by Gerrit Code Review
commit dad5bf0da5
16 changed files with 401 additions and 2 deletions

View File

@ -31,6 +31,22 @@ providing plugin mechanisms for all networking services exposed. The
consistent API is exposed to the user, but the internal implementation
is up to the chosen SDN.
Typical networking API request is an operation of create/update/delete:
* network
* subnet
* port
Neutron-server service is scheduled on nodes with
`openstack-control-plane=enabled` label.
neutron-rpc-server
~~~~~~~~~~~~~~~~~~
neutron-rpc-server is serving the networking PRC backend for neutron API
services. The internals of Neutron are highly flexible,
providing plugin mechanisms for all networking services exposed. The
consistent API is exposed to the user, but the internal implementation
is up to the chosen SDN.
Typical networking API request is an operation of create/update/delete:
* network
* subnet
@ -102,7 +118,7 @@ The above configuration options are handled by `neutron/values.yaml`:
type_drivers: flat,vlan,vxlan
Neutron-server service is scheduled on nodes with
Neutron-rpc-server service is scheduled on nodes with
`openstack-control-plane=enabled` label.
neutron-dhcp-agent
@ -220,6 +236,7 @@ Kubernetes resources should be deployed:
daemonset_ovs_agent: true
daemonset_sriov_agent: true
deployment_server: true
deployment_rpc_server: true
ingress_server: true
job_bootstrap: true
job_db_init: true

View File

@ -68,6 +68,7 @@ enabled:
daemonset_ovs_db: true
daemonset_ovs_vswitchd: true
deployment_server: true
deployment_rpc_server: true
ingress_server: true
job_db_init: true
job_db_sync: true
@ -129,6 +130,7 @@ should be enabled for below components:
configmap_bin: true
configmap_etc: true
deployment_server: true
deployment_rpc_server: true
ingress_server: true
job_db_init: true
job_db_sync: true

View File

@ -14,7 +14,7 @@ apiVersion: v1
appVersion: v1.0.0
description: OpenStack-Helm Neutron
name: neutron
version: 0.3.42
version: 0.3.43
home: https://docs.openstack.org/neutron/latest/
icon: https://www.openstack.org/themes/openstack/images/project-mascots/Neutron/OpenStack_Project_Neutron_vertical.png
sources:

View File

@ -0,0 +1,46 @@
#!/bin/bash
{{/*
Licensed 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.
*/}}
set -ex
COMMAND="${@:-start}"
function start () {
exec neutron-rpc-server \
--config-file /etc/neutron/neutron.conf \
{{- if ( has "ovn" .Values.network.backend ) }}
--config-file /tmp/pod-shared/ovn.ini \
{{- end }}
{{- if .Values.conf.plugins.taas.taas.enabled }}
--config-file /etc/neutron/taas_plugin.ini \
{{- end }}
{{- if ( has "sriov" .Values.network.backend ) }}
--config-file /etc/neutron/plugins/ml2/sriov_agent.ini \
{{- end }}
{{- if .Values.conf.plugins.l2gateway }}
--config-file /etc/neutron/l2gw_plugin.ini \
{{- end }}
{{- if ( has "tungstenfabric" .Values.network.backend ) }}
--config-file /etc/neutron/plugins/tungstenfabric/tf_plugin.ini
{{- else }}
--config-file /etc/neutron/plugins/ml2/ml2_conf.ini
{{- end }}
}
function stop () {
kill -TERM 1
}
$COMMAND

View File

@ -18,6 +18,17 @@ set -ex
COMMAND="${@:-start}"
function start () {
# (ricolin): Currently ovn have issue with uWSGI,
# let's keep using non-uWSGI way until this bug fixed:
# https://bugs.launchpad.net/neutron/+bug/1912359
{{- if ( has "ovn" .Values.network.backend ) }}
start_ovn
{{- else }}
exec uwsgi --ini /etc/neutron/neutron-api-uwsgi.ini
{{- end }}
}
function start_ovn () {
exec neutron-server \
--config-file /etc/neutron/neutron.conf \
{{- if ( has "ovn" .Values.network.backend ) }}

View File

@ -91,6 +91,8 @@ data:
{{- end }}
neutron-server.sh: |
{{ tuple "bin/_neutron-server.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
neutron-rpc-server.sh: |
{{ tuple "bin/_neutron-rpc-server.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
neutron-ironic-agent.sh: |
{{ tuple "bin/_neutron-ironic-agent.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
neutron-netns-cleanup-cron.sh: |

View File

@ -189,6 +189,14 @@ limitations under the License.
{{- if empty .Values.conf.neutron.DEFAULT.bind_port -}}
{{- $_ := tuple "network" "service" "api" . | include "helm-toolkit.endpoints.endpoint_port_lookup" | set .Values.conf.neutron.DEFAULT "bind_port" -}}
{{- end -}}
{{- if empty .Values.conf.neutron_api_uwsgi.uwsgi.processes -}}
{{- $_ := set .Values.conf.neutron_api_uwsgi.uwsgi "processes" .Values.conf.neutron.DEFAULT.api_workers -}}
{{- end -}}
{{- if empty (index .Values.conf.neutron_api_uwsgi.uwsgi "http-socket") -}}
{{- $http_socket_port := tuple "network" "service" "api" . | include "helm-toolkit.endpoints.endpoint_port_lookup" | toString }}
{{- $http_socket := printf "0.0.0.0:%s" $http_socket_port }}
{{- $_ := set .Values.conf.neutron_api_uwsgi.uwsgi "http-socket" $http_socket -}}
{{- end -}}
{{- if and (empty .Values.conf.logging.handler_fluent) (has "fluent" .Values.conf.logging.handlers.keys) -}}
{{- $fluentd_host := tuple "fluentd" "internal" $envAll | include "helm-toolkit.endpoints.hostname_namespaced_endpoint_lookup" }}
@ -284,6 +292,7 @@ data:
rally_tests.yaml: {{ toYaml $envAll.Values.conf.rally_tests.tests | b64enc }}
api-paste.ini: {{ include "helm-toolkit.utils.to_ini" $envAll.Values.conf.paste | b64enc }}
policy.yaml: {{ toYaml $envAll.Values.conf.policy | b64enc }}
neutron-api-uwsgi.ini: {{ include "helm-toolkit.utils.to_oslo_conf" .Values.conf.neutron_api_uwsgi | b64enc }}
neutron.conf: {{ include "helm-toolkit.utils.to_oslo_conf" $envAll.Values.conf.neutron | b64enc }}
logging.conf: {{ include "helm-toolkit.utils.to_oslo_conf" .Values.conf.logging | b64enc }}
api_audit_map.conf: {{ include "helm-toolkit.utils.to_oslo_conf" .Values.conf.api_audit_map | b64enc }}

View File

@ -0,0 +1,227 @@
{{/*
Licensed 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.
*/}}
{{- if .Values.manifests.deployment_rpc_server }}
{{- $envAll := . }}
{{- $dependencyOpts := dict "envAll" $envAll "dependencyMixinParam" $envAll.Values.network.backend "dependencyKey" "server" -}}
{{- $_ := include "helm-toolkit.utils.dependency_resolver" $dependencyOpts | toString | fromYaml }}
{{- $mounts_neutron_rpc_server := .Values.pod.mounts.neutron_rpc_server.neutron_rpc_server }}
{{- $mounts_neutron_rpc_server_init := .Values.pod.mounts.neutron_rpc_server.init_container }}
{{- $serviceAccountName := "neutron-rpc-server" }}
{{ tuple $envAll "pod_dependency" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: neutron-rpc-server
annotations:
{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" }}
labels:
{{ tuple $envAll "neutron" "rpc_server" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
spec:
replicas: {{ .Values.pod.replicas.rpc_server }}
selector:
matchLabels:
{{ tuple $envAll "neutron" "rpc_server" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 6 }}
{{ tuple $envAll | include "helm-toolkit.snippets.kubernetes_upgrades_deployment" | indent 2 }}
template:
metadata:
labels:
{{ tuple $envAll "neutron" "rpc_server" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
annotations:
{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }}
{{ dict "envAll" $envAll "podName" "neutron-rpc-server" "containerNames" (list "neutron-rpc-server" "init") | include "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" | indent 8 }}
spec:
{{ dict "envAll" $envAll "application" "neutron_rpc_server" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
serviceAccountName: {{ $serviceAccountName }}
affinity:
{{ tuple $envAll "neutron" "rpc_server" | include "helm-toolkit.snippets.kubernetes_pod_anti_affinity" | indent 8 }}
nodeSelector:
{{ .Values.labels.rpc_server.node_selector_key }}: {{ .Values.labels.rpc_server.node_selector_value }}
{{ if $envAll.Values.pod.tolerations.neutron.enabled }}
{{ tuple $envAll "neutron" | include "helm-toolkit.snippets.kubernetes_tolerations" | indent 6 }}
{{ end }}
terminationGracePeriodSeconds: {{ .Values.pod.lifecycle.termination_grace_period.rpc_server.timeout | default "30" }}
initContainers:
{{ tuple $envAll "pod_dependency" $mounts_neutron_rpc_server_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
{{- if ( has "ovn" .Values.network.backend ) }}
- name: ovn-neutron-init
{{ tuple $envAll "neutron_rpc_server" | include "helm-toolkit.snippets.image" | indent 10 }}
command:
- /tmp/neutron-ovn-init.sh
volumeMounts:
- name: pod-shared
mountPath: /tmp/pod-shared
- name: neutron-bin
mountPath: /tmp/neutron-ovn-init.sh
subPath: neutron-ovn-init.sh
readOnly: true
{{- end }}
{{- if ( has "tungstenfabric" .Values.network.backend ) }}
- name: tungstenfabric-neutron-init
image: {{ .Values.images.tags.tf_neutron_init }}
imagePullPolicy: {{ .Values.images.pull_policy }}
{{ tuple $envAll $envAll.Values.pod.resources.rpc_server | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
securityContext:
runAsUser: {{ .Values.pod.security_context.neutron_rpc_server.pod.runAsUser }}
env:
- name: OPENSTACK_VERSION
value: "{{ .Values.conf.openstack_version }}"
volumeMounts:
- name: neutron-plugin-shared
mountPath: /opt/plugin
{{- end }}
containers:
- name: neutron-rpc-server
{{ tuple $envAll "neutron_rpc_server" | include "helm-toolkit.snippets.image" | indent 10 }}
{{ tuple $envAll $envAll.Values.pod.resources.rpc_server | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
{{ dict "envAll" $envAll "application" "neutron_rpc_server" "container" "neutron_rpc_server" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
command:
- /tmp/neutron-rpc-server.sh
- start
{{- if or .Values.manifests.certificates .Values.tls.identity }}
env:
- name: REQUESTS_CA_BUNDLE
value: "/etc/neutron/certs/ca.crt"
{{- end }}
lifecycle:
preStop:
exec:
command:
- /tmp/neutron-rpc-server.sh
- stop
ports:
- name: q-api
containerPort: {{ tuple "network" "service" "api" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
volumeMounts:
- name: pod-tmp
mountPath: /tmp
- name: pod-shared
mountPath: /tmp/pod-shared
- name: pod-var-neutron
mountPath: {{ .Values.conf.neutron.DEFAULT.state_path }}
- name: neutron-bin
mountPath: /tmp/neutron-rpc-server.sh
subPath: neutron-rpc-server.sh
readOnly: true
- name: neutron-etc
mountPath: /etc/neutron/neutron.conf
subPath: neutron.conf
readOnly: true
- name: neutron-etc
mountPath: /etc/neutron/neutron-api-uwsgi.ini
subPath: neutron-api-uwsgi.ini
readOnly: true
{{- if .Values.conf.neutron.DEFAULT.log_config_append }}
- name: neutron-etc
mountPath: {{ .Values.conf.neutron.DEFAULT.log_config_append }}
subPath: {{ base .Values.conf.neutron.DEFAULT.log_config_append }}
readOnly: true
{{- end }}
- name: neutron-etc
mountPath: /etc/neutron/api_audit_map.conf
subPath: api_audit_map.conf
readOnly: true
{{- if( has "tungstenfabric" .Values.network.backend ) }}
- name: neutron-etc
mountPath: /etc/neutron/plugins/tungstenfabric/tf_plugin.ini
subPath: tf_plugin.ini
readOnly: true
- name: neutron-etc
mountPath: /etc/contrail/vnc_api_lib.ini
subPath: vnc_api_lib.ini
readOnly: true
- name: neutron-plugin-shared
mountPath: /opt/plugin
- name: neutron-bin
mountPath: /usr/local/lib/python2.7/site-packages/tf-plugin.pth
subPath: tf-plugin.pth
readOnly: true
- name: neutron-bin
mountPath: /var/lib/openstack/lib/python2.7/site-packages/tf-plugin.pth
subPath: tf-plugin.pth
readOnly: true
- name: neutron-bin
mountPath: /var/lib/openstack/lib/python3.6/site-packages/tf-plugin.pth
subPath: tf-plugin.pth
readOnly: true
{{- else }}
- name: neutron-etc
mountPath: /etc/neutron/plugins/ml2/ml2_conf.ini
subPath: ml2_conf.ini
readOnly: true
{{- end }}
{{ if ( has "sriov" .Values.network.backend ) }}
- name: neutron-etc
mountPath: /etc/neutron/plugins/ml2/sriov_agent.ini
subPath: sriov_agent.ini
readOnly: true
{{ end }}
{{- if .Values.conf.plugins.taas.taas.enabled }}
- name: neutron-etc
mountPath: /etc/neutron/taas_plugin.ini
subPath: taas_plugin.ini
readOnly: true
{{ end }}
{{- if .Values.conf.plugins.l2gateway }}
- name: neutron-etc
mountPath: /etc/neutron/l2gw_plugin.ini
subPath: l2gw_plugin.ini
readOnly: true
{{ end }}
- name: neutron-etc
mountPath: /etc/neutron/api-paste.ini
subPath: api-paste.ini
readOnly: true
- name: neutron-etc
mountPath: /etc/neutron/policy.yaml
subPath: policy.yaml
readOnly: true
{{- dict "enabled" .Values.manifests.certificates "name" .Values.endpoints.oslo_db.auth.admin.secret.tls.internal "path" "/etc/mysql/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
{{- dict "enabled" (or .Values.manifests.certificates .Values.tls.identity) "name" .Values.secrets.tls.network.server.internal "path" "/etc/neutron/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
{{- dict "enabled" $envAll.Values.manifests.certificates "name" $envAll.Values.endpoints.oslo_messaging.auth.admin.secret.tls.internal "path" "/etc/rabbitmq/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
{{ if $mounts_neutron_rpc_server.volumeMounts }}{{ toYaml $mounts_neutron_rpc_server.volumeMounts | indent 12 }}{{ end }}
volumes:
- name: pod-tmp
emptyDir: {}
- name: pod-shared
emptyDir: {}
{{- if .Values.manifests.certificates }}
- name: wsgi-neutron
emptyDir: {}
{{- end }}
- name: pod-var-neutron
emptyDir: {}
- name: neutron-bin
configMap:
name: neutron-bin
defaultMode: 0555
- name: neutron-etc
secret:
secretName: neutron-etc
defaultMode: 0444
{{- if ( has "tungstenfabric" .Values.network.backend ) }}
- name: neutron-plugin-shared
emptyDir: {}
{{- end }}
{{- dict "enabled" .Values.manifests.certificates "name" .Values.endpoints.oslo_db.auth.admin.secret.tls.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
{{- dict "enabled" (or .Values.manifests.certificates .Values.tls.identity) "name" .Values.secrets.tls.network.server.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
{{- dict "enabled" $envAll.Values.manifests.certificates "name" $envAll.Values.endpoints.oslo_messaging.auth.admin.secret.tls.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
{{ if $mounts_neutron_rpc_server.volumes }}{{ toYaml $mounts_neutron_rpc_server.volumes | indent 8 }}{{ end }}
{{- end }}

View File

@ -202,6 +202,10 @@ spec:
mountPath: /etc/neutron/neutron.conf
subPath: neutron.conf
readOnly: true
- name: neutron-etc
mountPath: /etc/neutron/neutron-api-uwsgi.ini
subPath: neutron-api-uwsgi.ini
readOnly: true
{{- if .Values.conf.neutron.DEFAULT.log_config_append }}
- name: neutron-etc
mountPath: {{ .Values.conf.neutron.DEFAULT.log_config_append }}

View File

@ -32,6 +32,7 @@ images:
ks_endpoints: docker.io/openstackhelm/heat:2024.1-ubuntu_jammy
netoffload: ghcr.io/vexxhost/netoffload:v1.0.1
neutron_server: docker.io/openstackhelm/neutron:2024.1-ubuntu_jammy
neutron_rpc_server: docker.io/openstackhelm/neutron:2024.1-ubuntu_jammy
neutron_dhcp: docker.io/openstackhelm/neutron:2024.1-ubuntu_jammy
neutron_metadata: docker.io/openstackhelm/neutron:2024.1-ubuntu_jammy
neutron_ovn_metadata: docker.io/openstackhelm/neutron:2024.1-ubuntu_jammy
@ -93,6 +94,9 @@ labels:
server:
node_selector_key: openstack-control-plane
node_selector_value: enabled
rpc_server:
node_selector_key: openstack-control-plane
node_selector_value: enabled
ironic_agent:
node_selector_key: openstack-control-plane
node_selector_value: enabled
@ -328,6 +332,19 @@ dependencies:
service: oslo_cache
- endpoint: internal
service: identity
rpc_server:
jobs:
- neutron-db-sync
- neutron-rabbit-init
services:
- endpoint: internal
service: oslo_db
- endpoint: internal
service: oslo_messaging
- endpoint: internal
service: oslo_cache
- endpoint: internal
service: identity
ironic_agent:
jobs:
- neutron-db-sync
@ -485,6 +502,19 @@ pod:
initialDelaySeconds: 60
periodSeconds: 15
timeoutSeconds: 10
rpc_server:
rpc_server:
readiness:
enabled: true
params:
periodSeconds: 15
timeoutSeconds: 10
liveness:
enabled: true
params:
initialDelaySeconds: 60
periodSeconds: 15
timeoutSeconds: 10
security_context:
neutron_dhcp_agent:
pod:
@ -585,6 +615,13 @@ pod:
neutron_server:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
neutron_rpc_server:
pod:
runAsUser: 42424
container:
neutron_rpc_server:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
neutron_sriov_agent:
pod:
runAsUser: 42424
@ -634,6 +671,11 @@ pod:
neutron_server:
volumeMounts:
volumes:
neutron_rpc_server:
init_container: null
neutron_rpc_server:
volumeMounts:
volumes:
neutron_dhcp_agent:
init_container: null
neutron_dhcp_agent:
@ -714,6 +756,7 @@ pod:
volumes:
replicas:
server: 1
rpc_server: 1
ironic_agent: 1
lifecycle:
upgrades:
@ -763,6 +806,8 @@ pod:
termination_grace_period:
server:
timeout: 30
rpc_server:
timeout: 30
ironic_agent:
timeout: 30
resources:
@ -1257,6 +1302,22 @@ conf:
paste.app_factory: neutron.api.v2.router:APIRouter.factory
filter:osprofiler:
paste.filter_factory: osprofiler.web:WsgiMiddleware.factory
neutron_api_uwsgi:
uwsgi:
add-header: "Connection: close"
buffer-size: 65535
die-on-term: true
enable-threads: true
exit-on-reload: false
hook-master-start: unix_signal:15 gracefully_kill_them_all
lazy-apps: true
log-x-forwarded-for: true
master: true
procname-prefix-spaced: "neutron-api:"
route-user-agent: '^kube-probe.* donotlog:'
thunder-lock: true
worker-reload-mercy: 80
wsgi-file: /var/lib/openstack/bin/neutron-api
policy: {}
api_audit_map:
DEFAULT:
@ -2522,6 +2583,7 @@ manifests:
daemonset_netns_cleanup_cron: true
deployment_ironic_agent: false
deployment_server: true
deployment_rpc_server: true
ingress_server: true
job_bootstrap: true
job_db_init: true

View File

@ -6,6 +6,8 @@ annotations:
custom.tld/key2: "value2"
neutron_server:
another.tld/foo: "bar"
neutron_rpc_server:
another.tld/foo: "bar"
secret:
default:
custom.tld/key: "value"

View File

@ -32,6 +32,9 @@ pod:
neutron-server: runtime/default
init: runtime/default
nginx: runtime/default
neutron-rpc-server:
neutron-rpc_server: runtime/default
init: runtime/default
neutron-test:
init: runtime/default
neutron-test: runtime/default

View File

@ -26,5 +26,6 @@ manifests:
daemonset_l3_agent: false
daemonset_metadata_agent: false
daemonset_ovs_agent: false
deployment_rpc_server: false
daemonset_ovn_metadata_agent: true

View File

@ -9,6 +9,9 @@ labels:
server:
node_selector_key: openstack-control-plane
node_selector_value: enabled
rpc_server:
node_selector_key: openstack-control-plane
node_selector_value: enabled
test:
node_selector_key: openstack-control-plane
node_selector_value: enabled

View File

@ -15,6 +15,12 @@ pod:
container:
neutron_server:
readOnlyRootFilesystem: false
neutron_rpc_server:
pod:
runAsUser: 0
container:
neutron_rpc_server:
readOnlyRootFilesystem: false
resources:
nginx:
requests:
@ -24,6 +30,9 @@ pod:
memory: "1024Mi"
cpu: "2000m"
conf:
neutron_api_uwsgi:
uwsgi:
http-socket: 127.0.0.1:9696
nginx: |
worker_processes 1;
daemon off;

View File

@ -84,4 +84,5 @@ neutron:
- 0.3.40 Fix ovs bridge creation in mappings for DPDK
- 0.3.41 Enable custom annotations for Openstack secrets
- 0.3.42 Update images used by default
- 0.3.43 Switch neutron to uWSGI
...