Browse Source

Implement Nova

- Add n-sch and n-meta-api
- Add n-cond
- Add novnc
- Add n-api
- Add n-cpu
- Stop nova on host

Change-Id: I6613bbe10502fa986c9f9961aae7e673ac462fc5
changes/51/748451/20
Mohammed Naser 1 year ago
committed by okozachenko
parent
commit
2f9cf0e387
  1. 1
      chart/templates/clusterrole.yaml
  2. 46
      devstack/lib/neutron-legacy
  3. 312
      devstack/lib/nova
  4. 13
      devstack/plugin.sh
  5. 54
      images/nova/Dockerfile
  6. 15
      images/nova/bindep.txt
  7. 1
      images/nova/build-requirements.txt
  8. 1
      images/nova/constraints.txt
  9. 28
      images/nova/nova-api-wsgi
  10. 29
      images/nova/nova-compute
  11. 29
      images/nova/nova-conductor
  12. 32
      images/nova/nova-init
  13. 28
      images/nova/nova-metadata-wsgi
  14. 29
      images/nova/nova-novncproxy
  15. 29
      images/nova/nova-scheduler
  16. 8
      images/nova/requirements.txt
  17. 91
      images/nova/setup-repos.sh
  18. 5
      openstack_operator/barbican.py
  19. 5
      openstack_operator/cinder.py
  20. 17
      openstack_operator/database.py
  21. 5
      openstack_operator/glance.py
  22. 5
      openstack_operator/heat.py
  23. 4
      openstack_operator/keystone.py
  24. 4
      openstack_operator/magnum.py
  25. 2
      openstack_operator/neutron.py
  26. 60
      openstack_operator/nova.py
  27. 4
      openstack_operator/objects.py
  28. 4
      openstack_operator/operator.py
  29. 5
      openstack_operator/placement.py
  30. 84
      openstack_operator/templates/nova/compute-api/daemonset.yml.j2
  31. 30
      openstack_operator/templates/nova/compute-api/service.yml.j2
  32. 102
      openstack_operator/templates/nova/compute/daemonset.yml.j2
  33. 68
      openstack_operator/templates/nova/conductor/daemonset.yml.j2
  34. 51
      openstack_operator/templates/nova/conductor/job.yml.j2
  35. 54
      openstack_operator/templates/nova/ingress.yml.j2
  36. 84
      openstack_operator/templates/nova/metadata-api/daemonset.yml.j2
  37. 30
      openstack_operator/templates/nova/metadata-api/service.yml.j2
  38. 84
      openstack_operator/templates/nova/novncproxy/daemonset.yml.j2
  39. 30
      openstack_operator/templates/nova/novncproxy/service.yml.j2
  40. 68
      openstack_operator/templates/nova/scheduler/daemonset.yml.j2
  41. 4
      playbooks/functional/devstack.yaml
  42. 15
      zuul.d/functional-jobs.yaml
  43. 9
      zuul.d/neutron-jobs.yaml
  44. 60
      zuul.d/nova-jobs.yaml

1
chart/templates/clusterrole.yaml

@ -76,6 +76,7 @@ rules:
- batch
resources:
- cronjobs
- jobs
verbs:
- create
- delete

46
devstack/lib/neutron-legacy

@ -251,3 +251,49 @@ function _neutron_ovs_base_configure_l3_agent {
echo noop
}
export -f _neutron_ovs_base_configure_l3_agent
function _create_nova_configs_neutron {
local conf=${1:-$NOVA_CONF}
kubernetes_ensure_resource secret/neutron-application-credential
NEUTRON_APPLICATION_CREDENTIAL_SECRET=$(get_data_from_secret neutron-application-credential openstack secret)
NEUTRON_APPLICATION_CREDENTIAL_ID=$(get_data_from_secret neutron-application-credential openstack id)
iniset $conf neutron auth_url $KEYSTONE_AUTH_URI_V3
iniset $conf neutron auth_type v3applicationcredential
iniset $conf neutron application_credential_id $NEUTRON_APPLICATION_CREDENTIAL_ID
iniset $conf neutron application_credential_secret $NEUTRON_APPLICATION_CREDENTIAL_SECRET
iniset $conf neutron auth_strategy "$Q_AUTH_STRATEGY"
# optionally set options in nova_conf
neutron_plugin_create_nova_conf $conf
if is_service_enabled q-meta; then
iniset $conf neutron service_metadata_proxy "True"
fi
iniset $conf DEFAULT vif_plugging_is_fatal "$VIF_PLUGGING_IS_FATAL"
iniset $conf DEFAULT vif_plugging_timeout "$VIF_PLUGGING_TIMEOUT"
}
function create_nova_conf_neutron {
_create_nova_configs_neutron $NOVA_CONF
_create_nova_configs_neutron $NOVA_CPU_CONF
}
export -f create_nova_conf_neutron
# NOTE(Alex): Change the nova metadata host
function _configure_neutron_metadata_agent {
cp $NEUTRON_DIR/etc/metadata_agent.ini.sample $Q_META_CONF_FILE
iniset $Q_META_CONF_FILE DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL
iniset $Q_META_CONF_FILE DEFAULT nova_metadata_host nova-metadata.openstack.svc
iniset $Q_META_CONF_FILE DEFAULT nova_metadata_port 80
iniset $Q_META_CONF_FILE DEFAULT metadata_workers $API_WORKERS
iniset $Q_META_CONF_FILE AGENT root_helper "$Q_RR_COMMAND"
if [[ "$Q_USE_ROOTWRAP_DAEMON" == "True" ]]; then
iniset $Q_META_CONF_FILE AGENT root_helper_daemon "$Q_RR_DAEMON_COMMAND"
fi
}
export -f _configure_neutron_metadata_agent

312
devstack/lib/nova

@ -14,6 +14,10 @@
# License for the specific language governing permissions and limitations
# under the License.
NOVA_STATE_PATH=/var/lib/nova
# INSTANCES_PATH is the previous name for this
NOVA_INSTANCES_PATH=$NOVA_STATE_PATH/instances
function create_nova_conf {
# Remove legacy ``nova.conf``
rm -f $NOVA_DIR/bin/nova.conf
@ -25,7 +29,6 @@ function create_nova_conf {
iniset $NOVA_CONF DEFAULT allow_resize_to_same_host "True"
fi
iniset $NOVA_CONF wsgi api_paste_config "$NOVA_API_PASTE_INI"
iniset $NOVA_CONF DEFAULT rootwrap_config "$NOVA_CONF_DIR/rootwrap.conf"
iniset $NOVA_CONF filter_scheduler enabled_filters "$NOVA_FILTERS"
iniset $NOVA_CONF scheduler workers "$API_WORKERS"
iniset $NOVA_CONF neutron default_floating_pool "$PUBLIC_NETWORK_NAME"
@ -47,56 +50,29 @@ function create_nova_conf {
iniset $NOVA_CONF DEFAULT bindir "/usr/bin"
fi
# only setup database connections and cache backend if there are services
# that require them running on the host. The ensures that n-cpu doesn't
# leak a need to use the db in a multinode scenario.
if is_service_enabled n-api n-cond n-sched; then
# If we're in multi-tier cells mode, we want our control services pointing
# at cell0 instead of cell1 to ensure isolation. If not, we point everything
# at the main database like normal.
if [[ "$CELLSV2_SETUP" == "singleconductor" ]]; then
local db="nova_cell1"
else
local db="nova_cell0"
# When in superconductor mode, nova-compute can't send instance
# info updates to the scheduler, so just disable it.
iniset $NOVA_CONF filter_scheduler track_instance_changes False
fi
kubernetes_ensure_resource secret/nova-cell1-mysql
NOVA_CELL1_DATABASE_USER=$(get_data_from_secret nova-cell1-mysql openstack USER)
NOVA_CELL1_DATABASE_PASSWORD=$(get_data_from_secret nova-cell1-mysql openstack PASSWORD)
NOVA_CELL1_DATABASE_NAME=$(get_data_from_secret nova-cell1-mysql openstack DATABASE)
iniset $NOVA_CONF database connection "mysql+pymysql://$NOVA_CELL1_DATABASE_USER:$NOVA_CELL1_DATABASE_PASSWORD@nova-cell1-mysql-master.openstack.svc/$NOVA_CELL1_DATABASE_NAME?charset=utf8"
kubernetes_ensure_resource secret/nova-api-mysql
NOVA_API_DATABASE_USER=$(get_data_from_secret nova-api-mysql openstack USER)
NOVA_API_DATABASE_PASSWORD=$(get_data_from_secret nova-api-mysql openstack PASSWORD)
NOVA_API_DATABASE_NAME=$(get_data_from_secret nova-api-mysql openstack DATABASE)
iniset $NOVA_CONF api_database connection "mysql+pymysql://$NOVA_API_DATABASE_USER:$NOVA_API_DATABASE_PASSWORD@nova-api-mysql-master.openstack.svc/$NOVA_API_DATABASE_NAME?charset=utf8"
# Cache related settings
# Those settings aren't really needed in n-cpu thus it is configured
# only on nodes which runs controller services
iniset $NOVA_CONF cache enabled $NOVA_ENABLE_CACHE
iniset $NOVA_CONF cache backend $CACHE_BACKEND
iniset $NOVA_CONF cache memcache_servers mcrouter-memcached-nova.openstack.svc.cluster.local
fi
kubernetes_ensure_resource secret/nova-cell1-mysql
NOVA_CELL1_DATABASE_USER=$(get_data_from_secret nova-cell1-mysql openstack USER)
NOVA_CELL1_DATABASE_PASSWORD=$(get_data_from_secret nova-cell1-mysql openstack PASSWORD)
NOVA_CELL1_DATABASE_NAME=$(get_data_from_secret nova-cell1-mysql openstack DATABASE)
iniset $NOVA_CONF database connection "mysql+pymysql://$NOVA_CELL1_DATABASE_USER:$NOVA_CELL1_DATABASE_PASSWORD@nova-cell1-mysql-master.openstack.svc/$NOVA_CELL1_DATABASE_NAME?charset=utf8"
if is_service_enabled n-api; then
if is_service_enabled n-api-meta; then
# If running n-api-meta as a separate service
NOVA_ENABLED_APIS=$(echo $NOVA_ENABLED_APIS | sed "s/,metadata//")
fi
iniset $NOVA_CONF DEFAULT enabled_apis "$NOVA_ENABLED_APIS"
if is_service_enabled tls-proxy && [ "$NOVA_USE_MOD_WSGI" == "False" ]; then
# Set the service port for a proxy to take the original
iniset $NOVA_CONF DEFAULT osapi_compute_listen_port "$NOVA_SERVICE_PORT_INT"
iniset $NOVA_CONF DEFAULT osapi_compute_link_prefix $NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT
fi
configure_keystone_authtoken_middleware $NOVA_CONF nova
fi
kubernetes_ensure_resource secret/nova-api-mysql
NOVA_API_DATABASE_USER=$(get_data_from_secret nova-api-mysql openstack USER)
NOVA_API_DATABASE_PASSWORD=$(get_data_from_secret nova-api-mysql openstack PASSWORD)
NOVA_API_DATABASE_NAME=$(get_data_from_secret nova-api-mysql openstack DATABASE)
iniset $NOVA_CONF api_database connection "mysql+pymysql://$NOVA_API_DATABASE_USER:$NOVA_API_DATABASE_PASSWORD@nova-api-mysql-master.openstack.svc/$NOVA_API_DATABASE_NAME?charset=utf8"
# Cache related settings
# Those settings aren't really needed in n-cpu thus it is configured
# only on nodes which runs controller services
iniset $NOVA_CONF cache enabled $NOVA_ENABLE_CACHE
iniset $NOVA_CONF cache backend $CACHE_BACKEND
iniset $NOVA_CONF cache memcache_servers mcrouter-memcached-nova.openstack.svc.cluster.local
NOVA_ENABLED_APIS=$(echo $NOVA_ENABLED_APIS | sed "s/,metadata//")
iniset $NOVA_CONF DEFAULT enabled_apis "$NOVA_ENABLED_APIS"
configure_keystone_authtoken_middleware $NOVA_CONF nova
if is_service_enabled cinder; then
configure_cinder_access
@ -121,12 +97,9 @@ function create_nova_conf {
iniset $NOVA_CONF DEFAULT mkisofs_cmd /usr/bin/mkisofs
fi
# Format logging
setup_logging $NOVA_CONF
iniset $NOVA_CONF upgrade_levels compute "auto"
write_uwsgi_config "$NOVA_UWSGI_CONF" "$NOVA_UWSGI" "/compute"
proxy_pass_to_kubernetes /compute nova nova-api-wsgi
write_uwsgi_config "$NOVA_METADATA_UWSGI_CONF" "$NOVA_METADATA_UWSGI" "" "$SERVICE_LISTEN_ADDRESS:${METADATA_SERVICE_PORT}"
if is_service_enabled ceilometer; then
@ -138,8 +111,6 @@ function create_nova_conf {
# Set the oslo messaging driver to the typical default. This does not
# enable notifications, but it will allow them to function when enabled.
iniset $NOVA_CONF oslo_messaging_notifications driver "messagingv2"
iniset $NOVA_CONF oslo_messaging_notifications transport_url $(get_notification_url)
iniset $NOVA_CONF notifications notification_format "$NOVA_NOTIFICATION_FORMAT"
kubernetes_ensure_resource secret/nova-cell1-rabbitmq
NOVA_RABBITMQ_USERNAME=$(get_data_from_secret nova-cell1-rabbitmq openstack username)
@ -151,11 +122,6 @@ function create_nova_conf {
# don't let the conductor get out of control now that we're using a pure python db driver
iniset $NOVA_CONF conductor workers "$API_WORKERS"
if is_service_enabled tls-proxy; then
iniset $NOVA_CONF DEFAULT glance_protocol https
iniset $NOVA_CONF oslo_middleware enable_proxy_headers_parsing True
fi
iniset $NOVA_CONF DEFAULT graceful_shutdown_timeout "$SERVICE_GRACEFUL_SHUTDOWN_TIMEOUT"
if [ "$NOVA_USE_SERVICE_TOKEN" == "True" ]; then
@ -195,58 +161,51 @@ function create_nova_conf {
# Console proxy configuration has to go after conductor configuration
# because the per cell config file nova_cellN.conf is cleared out as part
# of conductor configuration.
if [[ "${CELLSV2_SETUP}" == "singleconductor" ]]; then
configure_console_proxies
else
for i in $(seq 1 $NOVA_NUM_CELLS); do
local conf
local offset
conf=$(conductor_conf $i)
offset=$((i - 1))
configure_console_proxies $conf $offset
done
fi
configure_console_proxies
# NOTE(Alex): Disable rootwrap and use sudo only
iniset $NOVA_CONF workarounds disable_rootwrap True
}
function create_nova_compute_conf {
# Bug #1802143: $NOVA_CPU_CONF is constructed by first copying $NOVA_CONF...
cp $NOVA_CONF $NOVA_CPU_CONF
# ...and then adding/overriding anything explicitly set in $NOVA_CPU_CONF
merge_config_file $TOP_DIR/local.conf post-config '$NOVA_CPU_CONF'
if [[ "${CELLSV2_SETUP}" == "singleconductor" ]]; then
# NOTE(danms): Grenade doesn't setup multi-cell rabbit, so
# skip these bits and use the normal config.
echo "Skipping multi-cell conductor fleet setup"
else
# "${CELLSV2_SETUP}" is "superconductor"
# FIXME(danms): Should this be configurable?
iniset $NOVA_CPU_CONF workarounds disable_group_policy_check_upcall True
# Since the nova-compute service cannot reach nova-scheduler over
# RPC, we also disable track_instance_changes.
iniset $NOVA_CPU_CONF filter_scheduler track_instance_changes False
iniset_rpc_backend nova $NOVA_CPU_CONF DEFAULT "nova_cell${NOVA_CPU_CELL}"
fi
# Make sure we nuke any database config
inidelete $NOVA_CPU_CONF database connection
inidelete $NOVA_CPU_CONF api_database connection
# Console proxies were configured earlier in create_nova_conf. Now that the
# nova-cpu.conf has been created, configure the console settings required
# by the compute process.
configure_console_compute
}
export -f create_nova_compute_conf
function init_nova {
# All nova components talk to a central database.
# Only do this step once on the API node for an entire cluster.
if is_service_enabled $DATABASE_BACKENDS && is_service_enabled n-api; then
kubernetes_ensure_resource service/nova-api-mysql-master
kubernetes_wait_pod_ready nova-api-mysql-0
$NOVA_BIN_DIR/nova-manage --config-file $NOVA_CONF api_db sync
kubernetes_ensure_resource secret/nova-cell0-mysql
kubernetes_wait_pod_ready nova-cell0-mysql-0
NOVA_CELL0_DATABASE_USER=$(get_data_from_secret nova-cell0-mysql openstack USER)
NOVA_CELL0_DATABASE_PASSWORD=$(get_data_from_secret nova-cell0-mysql openstack PASSWORD)
NOVA_CELL0_DATABASE_NAME=$(get_data_from_secret nova-cell0-mysql openstack DATABASE)
kubernetes_ensure_resource service/nova-cell0-mysql-master
$NOVA_BIN_DIR/nova-manage cell_v2 map_cell0 --database_connection "mysql+pymysql://$NOVA_CELL0_DATABASE_USER:$NOVA_CELL0_DATABASE_PASSWORD@nova-cell0-mysql-master.openstack.svc/$NOVA_CELL0_DATABASE_NAME?charset=utf8"
# (Re)create nova databases
for i in $(seq 1 $NOVA_NUM_CELLS); do
$NOVA_BIN_DIR/nova-manage --config-file $(conductor_conf $i) db sync --local_cell
done
# Migrate nova and nova_cell0 databases.
$NOVA_BIN_DIR/nova-manage --config-file $NOVA_CONF db sync
# Run online migrations on the new databases
# Needed for flavor conversion
$NOVA_BIN_DIR/nova-manage --config-file $NOVA_CONF db online_data_migrations
# create the cell1 cell for the main nova db where the hosts live
for i in $(seq 1 $NOVA_NUM_CELLS); do
$NOVA_BIN_DIR/nova-manage --config-file $NOVA_CONF --config-file $(conductor_conf $i) cell_v2 create_cell --name "cell$i"
done
fi
create_nova_keys_dir
if [[ "$NOVA_BACKEND" == "LVM" ]]; then
init_default_lvm_volume_group
fi
}
@ -254,4 +213,143 @@ function init_nova {
function clean_iptables {
echo noop
}
export -f clean_iptables
export -f clean_iptables
# Configure access to placement from a nova service, usually
# compute, but sometimes conductor.
function configure_placement_nova_compute {
# Use the provided config file path or default to $NOVA_CONF.
local conf=${1:-$NOVA_CONF}
kubernetes_ensure_resource secret/placement-application-credential
PLACEMENT_APPLICATION_CREDENTIAL_SECRET=$(get_data_from_secret placement-application-credential openstack secret)
PLACEMENT_APPLICATION_CREDENTIAL_ID=$(get_data_from_secret placement-application-credential openstack id)
iniset $conf placement auth_url $KEYSTONE_AUTH_URI_V3
iniset $conf placement auth_type v3applicationcredential
iniset $conf placement application_credential_id $PLACEMENT_APPLICATION_CREDENTIAL_ID
iniset $conf placement application_credential_secret $PLACEMENT_APPLICATION_CREDENTIAL_SECRET
}
# Configure access to cinder.
function configure_cinder_access {
kubernetes_ensure_resource secret/cinder-application-credential
CINDER_APPLICATION_CREDENTIAL_SECRET=$(get_data_from_secret cinder-application-credential openstack secret)
CINDER_APPLICATION_CREDENTIAL_ID=$(get_data_from_secret cinder-application-credential openstack id)
iniset $NOVA_CONF cinder auth_url $KEYSTONE_AUTH_URI_V3
iniset $NOVA_CONF cinder auth_type v3applicationcredential
iniset $NOVA_CONF cinder application_credential_id $CINDER_APPLICATION_CREDENTIAL_ID
iniset $NOVA_CONF cinder application_credential_secret $CINDER_APPLICATION_CREDENTIAL_SECRET
}
# start_nova() - Start running processes
function start_nova_rest {
# Hack to set the path for rootwrap
local old_path=$PATH
export PATH=$NOVA_BIN_DIR:$PATH
# nova-scheduler
kubernetes_ensure_resource ds/nova-scheduler
kubernetes_rollout_restart ds/nova-scheduler
kubernetes_rollout_status ds/nova-scheduler
# nova-scheduler
kubernetes_ensure_resource ds/nova-metadata-api
kubernetes_rollout_restart ds/nova-metadata-api
kubernetes_rollout_status ds/nova-metadata-api
export PATH=$old_path
}
function start_nova_conductor {
kubernetes_ensure_resource ds/nova-conductor
kubernetes_rollout_restart ds/nova-conductor
kubernetes_rollout_status ds/nova-conductor
}
function start_nova_console_proxies {
# Hack to set the path for rootwrap
local old_path=$PATH
# This is needed to find the nova conf
export PATH=$NOVA_BIN_DIR:$PATH
local api_cell_conf=$NOVA_CONF
# novncproxy
kubernetes_ensure_resource ds/nova-novncproxy
kubernetes_rollout_restart ds/nova-novncproxy
kubernetes_rollout_status ds/nova-novncproxy
run_process n-xvnc "$NOVA_BIN_DIR/nova-xvpvncproxy --config-file $api_cell_conf"
run_process n-spice "$NOVA_BIN_DIR/nova-spicehtml5proxy --config-file $api_cell_conf --web $SPICE_WEB_DIR"
run_process n-sproxy "$NOVA_BIN_DIR/nova-serialproxy --config-file $api_cell_conf"
export PATH=$old_path
}
function configure_console_compute {
# NOTE(Alex): Now imagine using one cell and novnc only,
# so no need to offset the proxy port.
# Use the host IP instead of the service host because for multi-node, the
# service host will be the controller only.
local default_proxyclient_addr
default_proxyclient_addr=$(iniget $NOVA_CPU_CONF DEFAULT my_ip)
NOVNCPROXY_URL=${NOVNCPROXY_URL:-"http://nova-novncproxy.openstack.svc/vnc_auto.html"}
iniset $NOVA_CPU_CONF vnc novncproxy_base_url "$NOVNCPROXY_URL"
# Address on which instance vncservers will listen on compute hosts.
# For multi-host, this should be the management ip of the compute host.
VNCSERVER_LISTEN=${VNCSERVER_LISTEN:-$NOVA_SERVICE_LISTEN_ADDRESS}
VNCSERVER_PROXYCLIENT_ADDRESS=${VNCSERVER_PROXYCLIENT_ADDRESS:-$default_proxyclient_addr}
iniset $NOVA_CPU_CONF vnc server_listen "$VNCSERVER_LISTEN"
iniset $NOVA_CPU_CONF vnc server_proxyclient_address "$VNCSERVER_PROXYCLIENT_ADDRESS"
}
function configure_console_proxies {
# Use the provided config file path or default to $NOVA_CONF.
local conf=${1:-$NOVA_CONF}
# NOTE(Alex): Now imagine using one cell and novnc only,
# so no need to offset the proxy port.
iniset $conf vnc novncproxy_host "$NOVA_SERVICE_LISTEN_ADDRESS"
iniset $conf vnc novncproxy_port 6080
}
# start_nova_api() - Start the API process ahead of other things
function start_nova_api {
# Hack to set the path for rootwrap
local old_path=$PATH
export PATH=$NOVA_BIN_DIR:$PATH
kubernetes_ensure_resource ds/nova-compute-api
kubernetes_rollout_restart ds/nova-compute-api
kubernetes_rollout_status ds/nova-compute-api
export PATH=$old_path
}
# start_nova_compute() - Start the compute process
function start_nova_compute {
# Hack to set the path for rootwrap
local old_path=$PATH
export PATH=$NOVA_BIN_DIR:$PATH
# libvirt
kubernetes_ensure_resource ds/nova-compute
kubernetes_rollout_restart ds/nova-compute
kubernetes_rollout_status ds/nova-compute
export PATH=$old_path
}
# install_nova() - Collect source and prepare
# NOTE(Alex): Because, the nova stuff is in the stach.sh,
# keep nova installation on host.(kinda status check)
function start_nova {
start_nova_rest
start_nova_console_proxies
start_nova_conductor
start_nova_compute
}

13
devstack/plugin.sh

@ -51,8 +51,17 @@ elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then
sudo chmod -Rv 777 /etc/ceph
kubectl create secret generic ceph-config -n openstack \
--from-file=/etc/ceph/ceph.conf \
--from-file=/etc/ceph/ceph.client.glance.keyring \
--from-file=/etc/ceph/ceph.client.cinder.keyring
--from-file=/etc/ceph/ceph.client.cinder.keyring \
--from-file=/etc/ceph/ceph.client.glance.keyring
# NOTE(Alex): Create nova compute conf to include placement and libvirt config
create_nova_compute_conf
# NOTE(Alex) To include create_nova_conf_neutron and barbican hack config
kubectl create secret generic nova-config -n openstack \
--from-file=/etc/nova/nova.conf \
--from-file=/etc/nova/nova-cpu.conf \
--from-file=/etc/nova/nova_cell1.conf \
--from-file=/etc/nova/api-paste.ini
elif [[ "$1" == "stack" && "$2" == "extra" ]]; then
:

54
images/nova/Dockerfile

@ -0,0 +1,54 @@
# Copyright (c) 2020 VEXXHOST, Inc.
#
# 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.
FROM vexxhost/python-builder as builder
FROM vexxhost/python-base AS nova-base
RUN mkdir -p /var/lib/nova && \
chmod 777 -R /var/lib/nova
FROM nova-base AS nova-compute-api
COPY nova-api-wsgi /usr/local/bin/nova-api-wsgi
EXPOSE 8774
ENV UWSGI_HTTP_SOCKET=:8774 UWSGI_WSGI_FILE=/usr/local/bin/nova-api-wsgi
CMD ["/usr/local/bin/uwsgi", "--ini", "/etc/uwsgi/uwsgi.ini"]
FROM nova-base AS nova-metadata-api
COPY nova-metadata-wsgi /usr/local/bin/nova-metadata-wsgi
EXPOSE 8775
ENV UWSGI_HTTP_SOCKET=:8775 UWSGI_WSGI_FILE=/usr/local/bin/nova-metadata-wsgi
CMD ["/usr/local/bin/uwsgi", "--ini", "/etc/uwsgi/uwsgi.ini"]
FROM nova-base AS nova-conductor
COPY nova-init /usr/local/bin/nova-init
COPY nova-conductor /usr/local/bin/nova-conductor
CMD ["/usr/local/bin/nova-conductor"]
FROM nova-base AS nova-scheduler
COPY nova-scheduler /usr/local/bin/nova-scheduler
CMD ["/usr/local/bin/nova-scheduler"]
FROM debian:10-slim AS novnc-builder
ADD https://github.com/novnc/noVNC/archive/v1.2.0.tar.gz novnc.tgz
RUN tar -xvzf novnc.tgz
FROM nova-base AS nova-novncproxy
COPY nova-novncproxy /usr/local/bin/nova-novncproxy
COPY --from=novnc-builder noVNC-1.2.0/ /usr/share/novnc
EXPOSE 6080
CMD ["/usr/local/bin/nova-novncproxy"]
FROM nova-base AS nova-compute
COPY nova-compute /usr/local/bin/nova-compute
CMD ["/usr/local/bin/nova-compute"]

15
images/nova/bindep.txt

@ -0,0 +1,15 @@
gcc [compile]
libc-dev [compile]
pkg-config [compile]
libvirt-dev [compile]
librados-dev [compile]
librbd-dev [compile]
librados2
librbd1
libvirt0
ceph-common
genisoimage
open-iscsi
sudo
qemu-utils
openvswitch-common

1
images/nova/build-requirements.txt

@ -0,0 +1 @@
Cython

1
images/nova/constraints.txt

@ -0,0 +1 @@
--constraint https://releases.openstack.org/constraints/upper/ussuri

28
images/nova/nova-api-wsgi

@ -0,0 +1,28 @@
#!/usr/local/bin/python
# Copyright (c) 2020 VEXXHOST, Inc.
#
# 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.
import pkg_resources
import sentry_sdk
from nova.api.openstack.compute.wsgi import init_application
from sentry_sdk.integrations import wsgi
VERSION = pkg_resources.get_distribution("nova").version
sentry_sdk.init(release="nova@%s" % VERSION)
application = init_application()
application = wsgi.SentryWsgiMiddleware(application)

29
images/nova/nova-compute

@ -0,0 +1,29 @@
#!/usr/local/bin/python
# Copyright (c) 2020 VEXXHOST, Inc.
#
# 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.
import pkg_resources
import re
import sys
import sentry_sdk
from nova.cmd.compute import main
VERSION = pkg_resources.get_distribution("nova").version
sentry_sdk.init(release="nova@%s" % VERSION)
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

29
images/nova/nova-conductor

@ -0,0 +1,29 @@
#!/usr/local/bin/python
# Copyright (c) 2020 VEXXHOST, Inc.
#
# 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.
import pkg_resources
import re
import sys
import sentry_sdk
from nova.cmd.conductor import main
VERSION = pkg_resources.get_distribution("nova").version
sentry_sdk.init(release="nova@%s" % VERSION)
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

32
images/nova/nova-init

@ -0,0 +1,32 @@
#!/bin/bash
# Copyright (c) 2020 VEXXHOST, Inc.
#
# 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 -xe
nova-manage api_db sync
nova-manage cell_v2 map_cell0 --database_connection ${CELL0_DB}
# NOTE(Alex) Use same commands in devstack
nova-manage --config-file /etc/nova/nova_cell1.conf db sync --local_cell
nova-manage --config-file /etc/nova/nova.conf db sync
nova-manage --config-file /etc/nova/nova.conf db online_data_migrations
nova-manage --config-file /etc/nova/nova.conf \
--config-file /etc/nova/nova_cell1.conf \
cell_v2 create_cell --name cell1 || error_code=$?
if [ "${error_code}" -ne 2 ]; then
exit ${error_code}
fi

28
images/nova/nova-metadata-wsgi

@ -0,0 +1,28 @@
#!/usr/local/bin/python
# Copyright (c) 2020 VEXXHOST, Inc.
#
# 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.
import pkg_resources
import sentry_sdk
from nova.api.metadata.wsgi import init_application
from sentry_sdk.integrations import wsgi
VERSION = pkg_resources.get_distribution("nova").version
sentry_sdk.init(release="nova@%s" % VERSION)
application = init_application()
application = wsgi.SentryWsgiMiddleware(application)

29
images/nova/nova-novncproxy

@ -0,0 +1,29 @@
#!/usr/local/bin/python
# Copyright (c) 2020 VEXXHOST, Inc.
#
# 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.
import pkg_resources
import re
import sys
import sentry_sdk
from nova.cmd.novncproxy import main
VERSION = pkg_resources.get_distribution("nova").version
sentry_sdk.init(release="nova@%s" % VERSION)
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

29
images/nova/nova-scheduler

@ -0,0 +1,29 @@
#!/usr/local/bin/python
# Copyright (c) 2020 VEXXHOST, Inc.
#
# 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.
import pkg_resources
import re
import sys
import sentry_sdk
from nova.cmd.scheduler import main
VERSION = pkg_resources.get_distribution("nova").version
sentry_sdk.init(release="nova@%s" % VERSION)
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
images/nova/requirements.txt

@ -0,0 +1,8 @@
uWSGI
PyMySQL
python-memcached
sentry-sdk
git+https://opendev.org/openstack/nova@stable/ussuri
libvirt-python
https://github.com/ceph/ceph/archive/v15.2.4.tar.gz#egg=rados&subdirectory=src/pybind/rados
https://github.com/ceph/ceph/archive/v15.2.4.tar.gz#egg=rbd&subdirectory=src/pybind/rbd

91
images/nova/setup-repos.sh

@ -0,0 +1,91 @@
#!/bin/bash
# Copyright (c) 2020 VEXXHOST, Inc.
#
# 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 -xe
apt-get install -y gnupg2
cat <<EOF | apt-key add -
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2.0.22 (GNU/Linux)
mQINBF3u81cBEACbfsspk7WNkcXCn3N5T9VKYt/dmvSsEW8nIIf/iwV7dSISmruz
1b7bviqfekEvf37yiFwHVFxxS70ry/ofXp51X7RUVytrJY/hNMvr7C7zyNqM928+
c8TP3FjGsPvFiWw/L2JgGl9/4+OYW5yF3HabMOa63xbFPAU891o9HIN5YfFDZZWD
VNsMyXCUjVB9wy7anF77moqXuews1OmvMSArE7erLjAnC5HHGdTeZO7KfDCylqPB
oBWF3pzNU1Vu6wEq9vL5NDYglsbN7jmDA+8mS0SyAnFxvTsqjisR8gpNtPaatQqM
wTdOydscSoXS9MfpCrxPne0dBmpAlcVdI4hq1T4l9Osf2x5s+Kb9JxF+Q4V87n4q
8fjusePRIMxO7aZjFUEvL8uIzg7VvF3b1X9UXkS6LH2YPLOqOf3lhvyk5RwwMfHp
p99KOVrTWbaBYVKuxR17oWkYBPOPp+4ld8F6zSk36GK+lzPP8814X28kS357lg1y
4kla/CfNav3AXdnsZkCvJhrwwR8HCXwTYaF2TzrZPqv5TZB1k9iBuL2X52BSxobR
PvTTM00iZhipC/EsA7vQu4FOla/ySb/R6cfFIiDyOrDiOJ3+zlWDQ0uBikCP4lIY
uUB+uVIWd8F7Us1voqsqUrVL1CSu1cYn+NOhf12eZsA740wgUZfCU2qmGwARAQAB
tBhyZXBvIDxyZXBvQHZleHhob3N0Lm5ldD6JAjkEEwEIACMFAl3u81cCGy8HCwkI
BwMCAQYVCAIJCgsEFgIDAQIeAQIXgAAKCRDETupUFYbjJ7WxD/9HcMd9HMwg7WC3
eKSFeHGJXtN/0IuCJ6r3q10/dhb8QqqZ+Rnlr5CH4DAHdkhnL5+OvnHVYu/LVejX
17dZUS0uB+JXZpMdfsv8i2g/c8uxi2KPsRa3pxXudb+WhjbxhRxeMpsQNbMc5M5+
cYseUYj1nzTioDn9MQH43GcYBuhydiWsp7zRs2CNWrWJgwTOwnd/g4YV+9VWqshM
x+/N0bdD+LIT0MmYYGBaK6vBnM2kG6gcwc0ZMwMYHJk+MotuFNM7KDu06XWkp/Uq
8uzi7tZKHTa/kc+LrJrIOwLIkFH1uMvRZXma+JwASbcEW97YCUw/vhLa3AbZvCum
9QLHv28zyUXfo9QLEhkOGC/ykkYOSt0u/lznokpf840tmYHBCLavFzOPJ0Nc2T7Y
tCyEA5sV2UVI4hdBtwG1Vz8rAggDu0NWDW3BGyP0X2x1jddzzNRhevqQqcAe83Ei
XOOP1aunhtUKUe+sXLFOY0d3OK0RysKAn9kdxcZ9qqZdrKhj+dwuvMBeZPau0ZGT
t81b/zv6hiwA1b1b4X6EKz/aZwQyQ3/UUovM0KC9rMSzm5kKYWwcfkSDY6aLZtgc
GBc+auY+9Mwcp4V5kEH6zMXF4baJzMj2m7LFYlLRVofY5kxlrr86TAK0jMmiDOx8
AcjcZTiXBPNU8sK+VbsXvtB0Mel7Vw==
=hpXM
-----END PGP PUBLIC KEY BLOCK-----
EOF
cat <<EOF | tee /etc/apt/sources.list.d/vexxhost.list
deb http://repo.vexxhost.net/ buster main
EOF
cat <<EOF | apt-key add -
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1
mQINBFX4hgkBEADLqn6O+UFp+ZuwccNldwvh5PzEwKUPlXKPLjQfXlQRig1flpCH
E0HJ5wgGlCtYd3Ol9f9+qU24kDNzfbs5bud58BeE7zFaZ4s0JMOMuVm7p8JhsvkU
C/Lo/7NFh25e4kgJpjvnwua7c2YrA44ggRb1QT19ueOZLK5wCQ1mR+0GdrcHRCLr
7Sdw1d7aLxMT+5nvqfzsmbDullsWOD6RnMdcqhOxZZvpay8OeuK+yb8FVQ4sOIzB
FiNi5cNOFFHg+8dZQoDrK3BpwNxYdGHsYIwU9u6DWWqXybBnB9jd2pve9PlzQUbO
eHEa4Z+jPqxY829f4ldaql7ig8e6BaInTfs2wPnHJ+606g2UH86QUmrVAjVzlLCm
nqoGymoAPGA4ObHu9X3kO8viMBId9FzooVqR8a9En7ZE0Dm9O7puzXR7A1f5sHoz
JdYHnr32I+B8iOixhDUtxIY4GA8biGATNaPd8XR2Ca1hPuZRVuIiGG9HDqUEtXhV
fY5qjTjaThIVKtYgEkWMT+Wet3DPPiWT3ftNOE907e6EWEBCHgsEuuZnAbku1GgD
LBH4/a/yo9bNvGZKRaTUM/1TXhM5XgVKjd07B4cChgKypAVHvef3HKfCG2U/DkyA
LjteHt/V807MtSlQyYaXUTGtDCrQPSlMK5TjmqUnDwy6Qdq8dtWN3DtBWQARAQAB
tCpDZXBoLmNvbSAocmVsZWFzZSBrZXkpIDxzZWN1cml0eUBjZXBoLmNvbT6JAjgE
EwECACIFAlX4hgkCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEOhKwsBG
DzmUXdIQAI8YPcZMBWdv489q8CzxlfRIRZ3Gv/G/8CH+EOExcmkVZ89mVHngCdAP
DOYCl8twWXC1lwJuLDBtkUOHXNuR5+Jcl5zFOUyldq1Hv8u03vjnGT7lLJkJoqpG
l9QD8nBqRvBU7EM+CU7kP8+09b+088pULil+8x46PwgXkvOQwfVKSOr740Q4J4nm
/nUOyTNtToYntmt2fAVWDTIuyPpAqA6jcqSOC7Xoz9cYxkVWnYMLBUySXmSS0uxl
3p+wK0lMG0my/gb+alke5PAQjcE5dtXYzCn+8Lj0uSfCk8Gy0ZOK2oiUjaCGYN6D
u72qDRFBnR3jaoFqi03bGBIMnglGuAPyBZiI7LJgzuT9xumjKTJW3kN4YJxMNYu1
FzmIyFZpyvZ7930vB2UpCOiIaRdZiX4Z6ZN2frD3a/vBxBNqiNh/BO+Dex+PDfI4
TqwF8zlcjt4XZ2teQ8nNMR/D8oiYTUW8hwR4laEmDy7ASxe0p5aijmUApWq5UTsF
+s/QbwugccU0iR5orksM5u9MZH4J/mFGKzOltfGXNLYI6D5Mtwrnyi0BsF5eY0u6
vkdivtdqrq2DXY+ftuqLOQ7b+t1RctbcMHGPptlxFuN9ufP5TiTWSpfqDwmHCLsT
k2vFiMwcHdLpQ1IH8ORVRgPPsiBnBOJ/kIiXG2SxPUTjjEGOVgeA
=/Tod
-----END PGP PUBLIC KEY BLOCK-----
EOF
cat <<EOF | tee /etc/apt/sources.list.d/ceph.list
deb https://download.ceph.com/debian-octopus/ buster main
EOF

5
openstack_operator/barbican.py

@ -31,10 +31,7 @@ def create_or_resume(name, spec, **_):
"""
# deploy mysql for barbican
if "mysql" not in spec:
database.ensure_mysql_cluster("barbican", {})
else:
database.ensure_mysql_cluster("barbican", spec["mysql"])
database.ensure_mysql_cluster("barbican", spec=spec["mysql"])
# deploy barbican api
utils.create_or_update('barbican/daemonset.yml.j2',

5
openstack_operator/cinder.py

@ -32,10 +32,7 @@ def create_or_resume(name, spec, **_):
"""
# deploy mysql for cinder
if "mysql" not in spec:
database.ensure_mysql_cluster("cinder", {})
else:
database.ensure_mysql_cluster("cinder", spec["mysql"])
database.ensure_mysql_cluster("cinder", spec=spec["mysql"])
# deploy rabbitmq
if not utils.ensure_secret("openstack", "cinder-rabbitmq"):

17
openstack_operator/database.py

@ -20,24 +20,35 @@ This module contains a few common functions for database management
from openstack_operator import utils
def ensure_mysql_cluster(name, spec=None):
def ensure_mysql_cluster(name, user=None, database=None, spec=None):
"""Create or update mysql cluster"""
if spec is None:
spec = {}
if database is None:
database = name
if user is None:
user = database
config = utils.get_secret("openstack", name + "-mysql")
if config is None:
root_password = utils.generate_password()
password = utils.generate_password()
user = name
database = name
utils.create_or_update('mysqlcluster/secret-mysqlcluster.yml.j2',
name=name, user=user,
database=database, password=password,
rootPassword=root_password)
config = utils.get_secret("openstack", name + "-mysql")
config['connection'] = \
"mysql+pymysql://%s:%s@%s-mysql-master/%s?charset=utf8" % (
config["USER"],
config["PASSWORD"],
name,
config["DATABASE"]
)
utils.create_or_update('mysqlcluster/mysqlcluster.yml.j2',
server_side=False, name=name, spec=spec)
return config

5
openstack_operator/glance.py

@ -34,10 +34,7 @@ def create_or_resume(name, spec, **_):
"""
# deploy mysql for glance
if "mysql" not in spec:
database.ensure_mysql_cluster("glance", {})
else:
database.ensure_mysql_cluster("glance", spec["mysql"])
database.ensure_mysql_cluster("glance", spec=spec["mysql"])
# deploy glance api
utils.create_or_update('glance/daemonset.yml.j2',

5
openstack_operator/heat.py

@ -31,10 +31,7 @@ def create_or_resume(name, spec, **_):
"""Create and re-sync any Heat instances
"""
if "mysql" not in spec:
database.ensure_mysql_cluster("heat", {})
else:
database.ensure_mysql_cluster("heat", spec["mysql"])
database.ensure_mysql_cluster("heat", spec=spec["mysql"])
# deploy rabbitmq
if not utils.ensure_secret("openstack", "heat-rabbitmq"):

4
openstack_operator/keystone.py

@ -110,9 +110,7 @@ def create_or_resume(name, spec, **_):
# (TODO)Replace the current admin url
# deploy mysql
if "mysql" not in spec:
spec["mysql"] = {}
db_config = database.ensure_mysql_cluster("keystone", spec["mysql"])
db_config = database.ensure_mysql_cluster("keystone", spec=spec["mysql"])
# deploy memcached

4
openstack_operator/magnum.py

@ -33,9 +33,7 @@ def create_or_resume(name, spec, **_):
start the service up for the first time.
"""
if "mysql" not in spec:
spec["mysql"] = {}
database.ensure_mysql_cluster("magnum", spec["mysql"])
database.ensure_mysql_cluster("magnum", spec=spec["mysql"])
# deploy rabbitmq
if not utils.ensure_secret("openstack", "magnum-rabbitmq"):

2
openstack_operator/neutron.py

@ -37,7 +37,7 @@ def create_or_resume(spec, **_):
utils.create_or_update('neutron/secret-rabbitmq.yml.j2',
password=utils.generate_password())
database.ensure_mysql_cluster("neutron")
database.ensure_mysql_cluster("neutron", spec=spec["mysql"])
utils.create_or_update('neutron/rabbitmq.yml.j2')
utils.create_or_update('neutron/daemonset-server.yml.j2', spec=spec)

60
openstack_operator/nova.py

@ -19,7 +19,10 @@ This code takes care of doing the operations of the OpenStack Nova API
service.
"""
import kopf
from openstack_operator import database
from openstack_operator import identity
from openstack_operator import utils
MEMCACHED = True
@ -31,17 +34,24 @@ CELLS = [
]
def create_or_resume(**_):
def create_or_resume(spec, **_):
"""Create and re-sync a Nova instance
This function is called when a new resource is created but also when we
start the service up for the first time.
"""
database.ensure_mysql_cluster("nova-api")
databases = {}
identity.ensure_application_credential(name="nova")
databases['api'] = database.ensure_mysql_cluster(
"nova-api", database="nova_api"
)
for cell in CELLS:
database.ensure_mysql_cluster("nova-%s" % cell)
databases[cell] = database.ensure_mysql_cluster(
"nova-%s" % cell, database="nova_%s" % cell)
# NOTE(mnaser): cell0 does not need a message queue
if cell != 'cell0':
@ -50,3 +60,47 @@ def create_or_resume(**_):
component=cell,
password=utils.generate_password())
utils.create_or_update('nova/rabbitmq.yml.j2', component=cell)
utils.create_or_update('nova/conductor/daemonset.yml.j2', spec=spec)
utils.create_or_update('nova/scheduler/daemonset.yml.j2', spec=spec)
utils.create_or_update('nova/metadata-api/daemonset.yml.j2', spec=spec)
utils.create_or_update('nova/metadata-api/service.yml.j2')
utils.create_or_update('nova/novncproxy/daemonset.yml.j2', spec=spec)
utils.create_or_update('nova/novncproxy/service.yml.j2')
utils.create_or_update('nova/compute-api/daemonset.yml.j2', spec=spec)
utils.create_or_update('nova/compute-api/service.yml.j2')
utils.create_or_update('nova/compute/daemonset.yml.j2', spec=spec)
api_url = None
if "ingress" in spec:
utils.create_or_update('nova/ingress.yml.j2', spec=spec)
api_url = spec["ingress"]["host"]["api"]
if "endpoint" not in spec:
spec["endpoint"] = True
if spec["endpoint"]:
identity.ensure_service(name="nova",
service_type="compute",
url=api_url, path="/v2.1",
desc="OpenStack Compute")
@kopf.on.create('apps', 'v1', 'daemonsets', labels={
'app.kubernetes.io/managed-by': 'openstack-operator',
'app.kubernetes.io/name': 'nova',
'app.kubernetes.io/component': 'conductor',
})
def run_database_migrations(**_):
"""Run database migrations
This watches for any changes to the image ID for the Nova conductor
deployment and triggers a database migrations
"""
cell0 = database.ensure_mysql_cluster("nova-cell0")
utils.create_or_update('nova/conductor/job.yml.j2', adopt=True,
cell0_db=cell0['connection'])

4
openstack_operator/objects.py

@ -29,6 +29,7 @@ from pykube.objects import DaemonSet
from pykube.objects import Deployment
from pykube.objects import HorizontalPodAutoscaler
from pykube.objects import Ingress
from pykube.objects import Job
from pykube.objects import Namespace
from pykube.objects import NamespacedAPIObject
from pykube.objects import Pod
@ -128,6 +129,9 @@ MAPPING = {
"batch/v1beta1": {
"CronJob": CronJob,
},
"batch/v1": {
"Job": Job,
},
"extensions/v1beta1": {
"Ingress": Ingress
},

4
openstack_operator/operator.py

@ -103,7 +103,7 @@ def deploy(name, namespace, new, **_):
neutron.create_or_resume(spec)
if "nova" in config:
spec = set_service_config(config, "nova")
nova.create_or_resume()
nova.create_or_resume(spec)
if "horizon" in config:
spec = set_service_config(config, "horizon")
horizon.create_or_resume("horizon", spec)
@ -120,7 +120,7 @@ def deploy(name, namespace, new, **_):
spec = set_service_config(config, "magnum")
magnum.create_or_resume("magnum", spec)
if "barbican" in config:
spec = config["barbican"]
spec = set_service_config(config, "barbican")
barbican.create_or_resume("barbican", spec)
if "ceilometer" in config:
spec = config["ceilometer"]

5
openstack_operator/placement.py

@ -34,10 +34,7 @@ def create_or_resume(name, spec, **_):
"""
# deploy mysql for placement
if "mysql" not in spec:
database.ensure_mysql_cluster("placement", {})
else:
database.ensure_mysql_cluster("placement", spec["mysql"])
database.ensure_mysql_cluster("placement", spec=spec["mysql"])
# deploy placement api
utils.create_or_update('placement/daemonset.yml.j2', spec=spec)

84
openstack_operator/templates/nova/compute-api/daemonset.yml.j2

@ -0,0 +1,84 @@
---
# Copyright 2020 VEXXHOST, Inc.
#
# 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.
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nova-compute-api
namespace: openstack
labels:
{{ labels("nova", component="compute-api") | indent(4) }}
spec:
updateStrategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate
selector:
matchLabels:
{{ labels("nova", component="compute-api") | indent(6) }}
template:
metadata:
labels:
{{ labels("nova", component="compute-api") | indent(8) }}
spec:
automountServiceAccountToken: false
containers:
- name: compute-api
image: vexxhost/nova-compute-api:latest
imagePullPolicy: Always
env:
{% if 'sentryDSN' in spec %}
- name: SENTRY_DSN
value: {{ spec.sentryDSN }}
{% endif %}
- name: OS_DEFAULT__HOST
valueFrom:
fieldRef:
fieldPath: spec.nodeName
ports:
- name: nova-compute
protocol: TCP
containerPort: 8774
livenessProbe:
tcpSocket:
port: nova-compute
readinessProbe:
tcpSocket:
port: nova-compute
securityContext:
runAsUser: 1001
volumeMounts:
- name: config
mountPath: /etc/nova
- name: uwsgi-config
mountPath: /etc/uwsgi
volumes:
- name: config
secret:
secretName: nova-config
- name: uwsgi-config
configMap:
defaultMode: 420
name: uwsgi-default
nodeSelector:
node-role.kubernetes.io/master: ""
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
{% if 'hostAliases' in spec %}
hostAliases:
{{ spec.hostAliases | to_yaml | indent(8) }}
{% endif %}

30
openstack_operator/templates/nova/compute-api/service.yml.j2

@ -0,0 +1,30 @@
---
# Copyright 2020 VEXXHOST, Inc.
#
# 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.
apiVersion: v1
kind: Service
metadata:
name: nova
namespace: openstack
labels:
{{ labels("nova", component="compute-api") | indent(4) }}
spec:
ports:
- name: nova-compute
port: 80
protocol: TCP
targetPort: nova-compute
selector:
{{ labels("nova", component="compute-api") | indent(4) }}

102
openstack_operator/templates/nova/compute/daemonset.yml.j2

@ -0,0 +1,102 @@
---
# Copyright 2020 VEXXHOST, Inc.
#
# 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.
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nova-compute
namespace: openstack
labels:
{{ labels("nova", component="compute") | indent(4) }}
spec:
updateStrategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate
selector:
matchLabels:
{{ labels("nova", component="compute") | indent(6) }}
template:
metadata:
labels:
{{ labels("nova", component="compute") | indent(8) }}
spec:
automountServiceAccountToken: false
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
containers:
- name: compute
image: vexxhost/nova-compute:latest
imagePullPolicy: Always
command:
- nova-compute
- --config-file
- /etc/nova/nova-cpu.conf
env:
{% if 'sentryDSN' in spec %}
- name: SENTRY_DSN
value: {{ spec.sentryDSN }}
{% endif %}
- name: OS_DEFAULT__HOST
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: OS_VNC__SERVER_PROXYCLIENT_ADDRESS
valueFrom:
fieldRef:
fieldPath: status.hostIP
securityContext:
# NOTE(mnaser): We need to revisit this
privileged: true
volumeMounts:
- name: ceph
mountPath: /etc/ceph
- name: config
mountPath: /etc/nova
- name: state
mountPath: /var/lib/nova
- name: host-dev-pts
mountPath: /dev/pts
- name: host-run-libvirt
mountPath: /run/libvirt
- name: host-run-ovs
mountPath: /run/openvswitch
volumes:
- name: ceph
secret:
secretName: ceph-config
- name: config
secret:
secretName: nova-config
- name: state
hostPath:
path: /var/lib/nova
type: DirectoryOrCreate
- name: host-dev-pts
hostPath:
path: /dev/pts
- name: host-run-libvirt
hostPath:
path: /run/libvirt
- name: host-run-ovs
hostPath:
path: /run/openvswitch
nodeSelector:
node-role.openstack.org: compute
{% if 'hostAliases' in spec %}
hostAliases:
{{ spec.hostAliases | to_yaml | indent(8) }}
{% endif %}

68
openstack_operator/templates/nova/conductor/daemonset.yml.j2

@ -0,0 +1,68 @@
---
# Copyright 2020 VEXXHOST, Inc.
#
# 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.
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nova-conductor
namespace: openstack
labels:
{{ labels("nova", component="conductor") | indent(4) }}
spec:
updateStrategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate
selector:
matchLabels:
{{ labels("nova", component="conductor") | indent(6) }}
template:
metadata:
labels:
{{ labels("nova", component="conductor") | indent(8) }}
spec:
automountServiceAccountToken: false
containers:
- name: conductor
image: vexxhost/nova-conductor:latest
imagePullPolicy: Always
env:
{% if 'sentryDSN' in spec %}
- name: SENTRY_DSN
value: {{ spec.sentryDSN }}
{% endif %}
- name: OS_DEFAULT__HOST
valueFrom:
fieldRef:
fieldPath: spec.nodeName
securityContext:
runAsUser: 1001
volumeMounts:
- name: config
mountPath: /etc/nova
volumes:
- name: config
secret:
secretName: nova-config
nodeSelector:
node-role.kubernetes.io/master: ""
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
{% if 'hostAliases' in spec %}
hostAliases:
{{ spec.hostAliases | to_yaml | indent(8) }}
{% endif %}

51
openstack_operator/templates/nova/conductor/job.yml.j2

@ -0,0 +1,51 @@
---
# Copyright 2020 VEXXHOST, Inc.
#
# 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.
apiVersion: batch/v1
kind: Job
metadata:
name: nova-db-init
namespace: openstack
labels:
{{ labels("nova") | indent(4) }}
spec:
template:
metadata:
labels:
{{ labels("nova") | indent(8) }}
spec:
automountServiceAccountToken: false
restartPolicy: OnFailure
containers:
- name: nova-init
image: vexxhost/nova-conductor:latest
imagePullPolicy: Always
command:
- nova-init
env:
- name: CELL0_DB
value: {{ cell0_db }}
volumeMounts:
- name: config
mountPath: /etc/nova
volumes:
- name: config
secret:
secretName: nova-config
nodeSelector:
node-role.kubernetes.io/master: ""
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule

54
openstack_operator/templates/nova/ingress.yml.j2

@ -0,0 +1,54 @@
---
# Copyright 2020 VEXXHOST, Inc.
#
# 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.
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: nova
namespace: openstack
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
certmanager.k8s.io/cluster-issuer: "letsencrypt-prod"
spec:
{% if spec.ingress.host is defined %}
rules:
{% if spec.ingress.host.api is defined %}
- host: {{ spec.ingress.host.api }}
http:
paths:
- path: /
backend:
serviceName: nova
servicePort: 80
{% endif %}
{% if spec.ingress.host.vnc is defined %}
- host: {{ spec.ingress.host.vnc }}
http:
paths:
- path: /
backend:
serviceName: nova-novncproxy
servicePort: 80
{% endif %}
tls:
- hosts:
{% if spec.ingress.host.api is defined %}
- {{ spec.ingress.host.api }}
{% endif %}
{% if spec.ingress.host.vnc is defined %}
- {{ spec.ingress.host.vnc }}
{% endif %}
secretName: nova-tls
{% endif %}

84
openstack_operator/templates/nova/metadata-api/daemonset.yml.j2

@ -0,0 +1,84 @@
---
# Copyright 2020 VEXXHOST, Inc.
#
# 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.
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nova-metadata-api
namespace: openstack
labels:
{{ labels("nova", component="metadata-api") | indent(4) }}
spec:
updateStrategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate
selector:
matchLabels:
{{ labels("nova", component="metadata-api") | indent(6) }}
template:
metadata:
labels:
{{ labels("nova", component="metadata-api") | indent(8) }}
spec:
automountServiceAccountToken: false
containers:
- name: metadata-api
image: vexxhost/nova-metadata-api:latest
imagePullPolicy: Always
env:
{% if 'sentryDSN' in spec %}
- name: SENTRY_DSN
value: {{ spec.sentryDSN }}
{% endif %}
- name: OS_DEFAULT__HOST
valueFrom:
fieldRef:
fieldPath: spec.nodeName
ports:
- name: nova-metadata
protocol: TCP
containerPort: 8775
livenessProbe:
tcpSocket:
port: nova-metadata
readinessProbe:
tcpSocket:
port: nova-metadata
securityContext:
runAsUser: 1001
volumeMounts:
- name: config
mountPath: /etc/nova
- name: uwsgi-config
mountPath: /etc/uwsgi
volumes:
- name: config
secret:
secretName: nova-config
- name: uwsgi-config
configMap:
defaultMode: 420
name: uwsgi-default
nodeSelector:
node-role.kubernetes.io/master: ""
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
{% if 'hostAliases' in spec %}
hostAliases:
{{ spec.hostAliases | to_yaml | indent(8) }}
{% endif %}

30
openstack_operator/templates/nova/metadata-api/service.yml.j2

@ -0,0 +1,30 @@
---
# Copyright 2020 VEXXHOST, Inc.
#
# 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.
apiVersion: v1
kind: Service
metadata:
name: nova-metadata
namespace: openstack
labels:
{{ labels("nova", component="metadata-api") | indent(4) }}
spec:
ports:
- name: nova-metadata
port: 80
protocol: TCP
targetPort: nova-metadata
selector:
{{ labels("nova", component="metadata-api") | indent(4) }}

84
openstack_operator/templates/nova/novncproxy/daemonset.yml.j2

@ -0,0 +1,84 @@
---
# Copyright 2020 VEXXHOST, Inc.
#
# 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.
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nova-novncproxy
namespace: openstack
labels:
{{ labels("nova", component="novncproxy") | indent(4) }}
spec:
updateStrategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate
selector:
matchLabels:
{{ labels("nova", component="novncproxy") | indent(6) }}
template:
metadata:
labels:
{{ labels("nova", component="novncproxy") | indent(8) }}
spec:
automountServiceAccountToken: false
containers:
- name: novncproxy
image: vexxhost/nova-novncproxy:latest
imagePullPolicy: Always
env:
{% if 'sentryDSN' in spec %}
- name: SENTRY_DSN
value: {{ spec.sentryDSN }}
{% endif %}
- name: OS_DEFAULT__HOST
valueFrom:
fieldRef:
fieldPath: spec.nodeName
ports:
- name: nova-novncproxy
protocol: TCP
containerPort: 6080
livenessProbe:
tcpSocket:
port: nova-novncproxy
readinessProbe:
tcpSocket:
port: nova-novncproxy
securityContext:
runAsUser: 1001
volumeMounts:
- name: config
mountPath: /etc/nova
- name: uwsgi-config
mountPath: /etc/uwsgi
volumes:
- name: config
secret:
secretName: nova-config