Browse code

Add support for Docker as Nova hypervisor

* Add basic support for hypervisor plugins in lib/nova_plugins
* Add lib/nova_plugins/hypervisor-docker to use Docker as a Nova
hypervisor.
* Add tools/install_docker.sh to install the Docker daemon and
registry container, download base image and import
* Configure Nova to use docker plugin
* Add docker exercise and skip unsupported ones

Nova blueprint: new-hypervisor-docker

Change-Id: I9e7065b562dce2ce853def583ab1165886612227

Dean Troyer authored on 2013/08/05 09:53:19
Showing 14 changed files
... ...
@@ -12,10 +12,14 @@ Read more at http://devstack.org (built from the gh-pages branch)
12 12
 
13 13
 IMPORTANT: Be sure to carefully read `stack.sh` and any other scripts you execute before you run them, as they install software and may alter your networking configuration.  We strongly recommend that you run `stack.sh` in a clean and disposable vm when you are first getting started.
14 14
 
15
-# Devstack on Xenserver
15
+# DevStack on Xenserver
16 16
 
17 17
 If you would like to use Xenserver as the hypervisor, please refer to the instructions in `./tools/xen/README.md`.
18 18
 
19
+# DevStack on Docker
20
+
21
+If you would like to use Docker as the hypervisor, please refer to the instructions in `./tools/docker/README.md`.
22
+
19 23
 # Versions
20 24
 
21 25
 The devstack master branch generally points to trunk versions of OpenStack components.  For older, stable versions, look for branches named stable/[release] in the DevStack repo.  For example, you can do the following to create a diablo OpenStack cloud:
... ...
@@ -64,6 +64,11 @@ cleanup_nova
64 64
 cleanup_neutron
65 65
 cleanup_swift
66 66
 
67
+# Do the hypervisor cleanup until this can be moved back into lib/nova
68
+if [[ -r $NOVA_PLUGINS/hypervisor-$VIRT_DRIVER ]]; then
69
+    cleanup_nova_hypervisor
70
+fi
71
+
67 72
 # cinder doesn't always clean up the volume group as it might be used elsewhere...
68 73
 # clean it up if it is a loop device
69 74
 VG_DEV=$(sudo losetup -j $DATA_DIR/${VOLUME_GROUP}-backing-file | awk -F':' '/backing-file/ { print $1}')
... ...
@@ -44,6 +44,9 @@ source $TOP_DIR/exerciserc
44 44
 # the exercise is skipped
45 45
 is_service_enabled cinder || exit 55
46 46
 
47
+# Also skip if the hypervisor is Docker
48
+[[ "$VIRT_DRIVER" == "docker" ]] && exit 55
49
+
47 50
 # Instance type to create
48 51
 DEFAULT_INSTANCE_TYPE=${DEFAULT_INSTANCE_TYPE:-m1.tiny}
49 52
 
50 53
new file mode 100755
... ...
@@ -0,0 +1,105 @@
0
+#!/usr/bin/env bash
1
+
2
+# **docker**
3
+
4
+# Test Docker hypervisor
5
+
6
+echo "*********************************************************************"
7
+echo "Begin DevStack Exercise: $0"
8
+echo "*********************************************************************"
9
+
10
+# This script exits on an error so that errors don't compound and you see
11
+# only the first error that occurred.
12
+set -o errexit
13
+
14
+# Print the commands being run so that we can see the command that triggers
15
+# an error.  It is also useful for following allowing as the install occurs.
16
+set -o xtrace
17
+
18
+
19
+# Settings
20
+# ========
21
+
22
+# Keep track of the current directory
23
+EXERCISE_DIR=$(cd $(dirname "$0") && pwd)
24
+TOP_DIR=$(cd $EXERCISE_DIR/..; pwd)
25
+
26
+# Import common functions
27
+source $TOP_DIR/functions
28
+
29
+# Import configuration
30
+source $TOP_DIR/openrc
31
+
32
+# Import exercise configuration
33
+source $TOP_DIR/exerciserc
34
+
35
+# Skip if the hypervisor is not Docker
36
+[[ "$VIRT_DRIVER" == "docker" ]] || exit 55
37
+
38
+# Import docker functions and declarations
39
+source $TOP_DIR/lib/nova_plugins/hypervisor-docker
40
+
41
+# Image and flavor are ignored but the CLI requires them...
42
+
43
+# Instance type to create
44
+DEFAULT_INSTANCE_TYPE=${DEFAULT_INSTANCE_TYPE:-m1.tiny}
45
+
46
+# Boot this image, use first AMI image if unset
47
+DEFAULT_IMAGE_NAME=${DEFAULT_IMAGE_NAME:-ami}
48
+
49
+# Instance name
50
+VM_NAME=ex-docker
51
+
52
+
53
+# Launching a server
54
+# ==================
55
+
56
+# Grab the id of the image to launch
57
+IMAGE=$(glance image-list | egrep " $DOCKER_IMAGE_NAME:latest " | get_field 1)
58
+die_if_not_set $LINENO IMAGE "Failure getting image $DOCKER_IMAGE_NAME"
59
+
60
+# Select a flavor
61
+INSTANCE_TYPE=$(nova flavor-list | grep $DEFAULT_INSTANCE_TYPE | get_field 1)
62
+if [[ -z "$INSTANCE_TYPE" ]]; then
63
+    # grab the first flavor in the list to launch if default doesn't exist
64
+   INSTANCE_TYPE=$(nova flavor-list | head -n 4 | tail -n 1 | get_field 1)
65
+fi
66
+
67
+# Clean-up from previous runs
68
+nova delete $VM_NAME || true
69
+if ! timeout $ACTIVE_TIMEOUT sh -c "while nova show $VM_NAME; do sleep 1; done"; then
70
+    die $LINENO "server didn't terminate!"
71
+fi
72
+
73
+# Boot instance
74
+# -------------
75
+
76
+VM_UUID=$(nova boot --flavor $INSTANCE_TYPE --image $IMAGE $VM_NAME | grep ' id ' | get_field 2)
77
+die_if_not_set $LINENO VM_UUID "Failure launching $VM_NAME"
78
+
79
+# Check that the status is active within ACTIVE_TIMEOUT seconds
80
+if ! timeout $ACTIVE_TIMEOUT sh -c "while ! nova show $VM_UUID | grep status | grep -q ACTIVE; do sleep 1; done"; then
81
+    die $LINENO "server didn't become active!"
82
+fi
83
+
84
+# Get the instance IP
85
+IP=$(nova show $VM_UUID | grep "$PRIVATE_NETWORK_NAME" | get_field 2)
86
+die_if_not_set $LINENO IP "Failure retrieving IP address"
87
+
88
+# Private IPs can be pinged in single node deployments
89
+ping_check "$PRIVATE_NETWORK_NAME" $IP $BOOT_TIMEOUT
90
+
91
+# Clean up
92
+# --------
93
+
94
+# Delete instance
95
+nova delete $VM_UUID || die $LINENO "Failure deleting instance $VM_NAME"
96
+if ! timeout $TERMINATE_TIMEOUT sh -c "while nova list | grep -q $VM_UUID; do sleep 1; done"; then
97
+    die $LINENO "Server $VM_NAME not deleted"
98
+fi
99
+
100
+set +o xtrace
101
+echo "*********************************************************************"
102
+echo "SUCCESS: End DevStack Exercise: $0"
103
+echo "*********************************************************************"
104
+
... ...
@@ -41,6 +41,9 @@ fi
41 41
 # Import exercise configuration
42 42
 source $TOP_DIR/exerciserc
43 43
 
44
+# Skip if the hypervisor is Docker
45
+[[ "$VIRT_DRIVER" == "docker" ]] && exit 55
46
+
44 47
 # Instance type to create
45 48
 DEFAULT_INSTANCE_TYPE=${DEFAULT_INSTANCE_TYPE:-m1.tiny}
46 49
 
... ...
@@ -38,6 +38,9 @@ fi
38 38
 # Import exercise configuration
39 39
 source $TOP_DIR/exerciserc
40 40
 
41
+# Skip if the hypervisor is Docker
42
+[[ "$VIRT_DRIVER" == "docker" ]] && exit 55
43
+
41 44
 # Instance type to create
42 45
 DEFAULT_INSTANCE_TYPE=${DEFAULT_INSTANCE_TYPE:-m1.tiny}
43 46
 
... ...
@@ -33,6 +33,9 @@ source $TOP_DIR/openrc
33 33
 # Import exercise configuration
34 34
 source $TOP_DIR/exerciserc
35 35
 
36
+# Skip if the hypervisor is Docker
37
+[[ "$VIRT_DRIVER" == "docker" ]] && exit 55
38
+
36 39
 
37 40
 # Testing Security Groups
38 41
 # =======================
... ...
@@ -42,6 +42,9 @@ source $TOP_DIR/exerciserc
42 42
 # exercise is skipped.
43 43
 is_service_enabled cinder || exit 55
44 44
 
45
+# Also skip if the hypervisor is Docker
46
+[[ "$VIRT_DRIVER" == "docker" ]] && exit 55
47
+
45 48
 # Instance type to create
46 49
 DEFAULT_INSTANCE_TYPE=${DEFAULT_INSTANCE_TYPE:-m1.tiny}
47 50
 
... ...
@@ -169,6 +169,13 @@ function cleanup_nova() {
169 169
     fi
170 170
 
171 171
     sudo rm -rf $NOVA_STATE_PATH $NOVA_AUTH_CACHE_DIR
172
+
173
+    # NOTE(dtroyer): This really should be called from here but due to the way
174
+    #                nova abuses the _cleanup() function we're moving it
175
+    #                directly into cleanup.sh until this can be fixed.
176
+    #if is_service_enabled n-cpu && [[ -r $NOVA_PLUGINS/hypervisor-$VIRT_DRIVER ]]; then
177
+    #    cleanup_nova_hypervisor
178
+    #fi
172 179
 }
173 180
 
174 181
 # configure_nova_rootwrap() - configure Nova's rootwrap
... ...
@@ -650,7 +657,9 @@ function install_novaclient() {
650 650
 # install_nova() - Collect source and prepare
651 651
 function install_nova() {
652 652
     if is_service_enabled n-cpu; then
653
-        if [[ "$VIRT_DRIVER" = 'libvirt' ]]; then
653
+        if [[ -r $NOVA_PLUGINS/hypervisor-$VIRT_DRIVER ]]; then
654
+            install_nova_hypervisor
655
+        elif [[ "$VIRT_DRIVER" = 'libvirt' ]]; then
654 656
             if is_ubuntu; then
655 657
                 install_package kvm
656 658
                 install_package libvirt-bin
... ...
@@ -728,6 +737,9 @@ function start_nova() {
728 728
            screen_it n-cpu "cd $NOVA_DIR && $NOVA_BIN_DIR/nova-compute --config-file $NOVA_CONF_BOTTOM"
729 729
        done
730 730
     else
731
+        if is_service_enabled n-cpu && [[ -r $NOVA_PLUGINS/hypervisor-$VIRT_DRIVER ]]; then
732
+            start_nova_hypervisor
733
+        fi
731 734
         screen_it n-cpu "cd $NOVA_DIR && $NOVA_BIN_DIR/nova-compute --config-file $NOVA_CONF_BOTTOM"
732 735
     fi
733 736
     screen_it n-crt "cd $NOVA_DIR && $NOVA_BIN_DIR/nova-cert"
... ...
@@ -754,6 +766,9 @@ function stop_nova() {
754 754
     for serv in n-api n-cpu n-crt n-net n-sch n-novnc n-xvnc n-cauth n-spice n-cond n-cond n-cell n-cell n-api-meta; do
755 755
         screen -S $SCREEN_NAME -p $serv -X kill
756 756
     done
757
+    if is_service_enabled n-cpu && [[ -r $NOVA_PLUGINS/hypervisor-$VIRT_DRIVER ]]; then
758
+        stop_nova_hypervisor
759
+    fi
757 760
 }
758 761
 
759 762
 
760 763
new file mode 100644
... ...
@@ -0,0 +1,132 @@
0
+# lib/nova_plugins/docker
1
+# Configure the Docker hypervisor
2
+
3
+# Enable with:
4
+# VIRT_DRIVER=docker
5
+
6
+# Dependencies:
7
+# ``functions`` file
8
+# ``nova`` and ``glance`` configurations
9
+
10
+# install_nova_hypervisor - install any external requirements
11
+# configure_nova_hypervisor - make configuration changes, including those to other services
12
+# start_nova_hypervisor - start any external services
13
+# stop_nova_hypervisor - stop any external services
14
+# cleanup_nova_hypervisor - remove transient data and cache
15
+
16
+# Save trace setting
17
+MY_XTRACE=$(set +o | grep xtrace)
18
+set +o xtrace
19
+
20
+
21
+# Defaults
22
+# --------
23
+
24
+# Set up default directories
25
+DOCKER_DIR=$DEST/docker
26
+DOCKER_REPO=${DOCKER_REPO:-https://github.com/dotcloud/openstack-docker.git}
27
+DOCKER_BRANCH=${DOCKER_BRANCH:-master}
28
+
29
+DOCKER_UNIX_SOCKET=/var/run/docker.sock
30
+DOCKER_PID_FILE=/var/run/docker.pid
31
+DOCKER_REGISTRY_PORT=${DOCKER_REGISTRY_PORT:-5042}
32
+
33
+DOCKER_IMAGE=${DOCKER_IMAGE:-http://get.docker.io/images/openstack/docker-ut.tar.gz}
34
+DOCKER_IMAGE_NAME=docker-busybox
35
+DOCKER_REGISTRY_IMAGE=${DOCKER_REGISTRY_IMAGE:-http://get.docker.io/images/openstack/docker-registry.tar.gz}
36
+DOCKER_REGISTRY_IMAGE_NAME=docker-registry
37
+DOCKER_REPOSITORY_NAME=${SERVICE_HOST}:${DOCKER_REGISTRY_PORT}/${DOCKER_IMAGE_NAME}
38
+
39
+DOCKER_PACKAGE_VERSION=${DOCKER_PACKAGE_VERSION:-0.6.1}
40
+DOCKER_APT_REPO=${DOCKER_APT_REPO:-https://get.docker.io/ubuntu}
41
+
42
+
43
+# Entry Points
44
+# ------------
45
+
46
+# clean_nova_hypervisor - Clean up an installation
47
+function cleanup_nova_hypervisor() {
48
+    stop_service docker
49
+
50
+    # Clean out work area
51
+    sudo rm -rf /var/lib/docker
52
+}
53
+
54
+# configure_nova_hypervisor - Set config files, create data dirs, etc
55
+function configure_nova_hypervisor() {
56
+    git_clone $DOCKER_REPO $DOCKER_DIR $DOCKER_BRANCH
57
+
58
+    ln -snf ${DOCKER_DIR}/nova-driver $NOVA_DIR/nova/virt/docker
59
+
60
+    iniset $NOVA_CONF DEFAULT compute_driver docker.DockerDriver
61
+    iniset $GLANCE_API_CONF DEFAULT container_formats ami,ari,aki,bare,ovf,docker
62
+
63
+    sudo cp -p ${DOCKER_DIR}/nova-driver/docker.filters $NOVA_CONF_DIR/rootwrap.d
64
+}
65
+
66
+# install_nova_hypervisor() - Install external components
67
+function install_nova_hypervisor() {
68
+    # So far this is Ubuntu only
69
+    if ! is_ubuntu; then
70
+        die $LINENO "Docker is only supported on Ubuntu at this time"
71
+    fi
72
+
73
+    # Make sure Docker is installed
74
+    if ! is_package_installed lxc-docker; then
75
+        die $LINENO "Docker is not installed.  Please run tools/docker/install_docker.sh"
76
+    fi
77
+
78
+    local docker_pid
79
+    read docker_pid <$DOCKER_PID_FILE
80
+    if [[ -z $docker_pid ]] || ! ps -p $docker_pid | grep [d]ocker; then
81
+        die $LINENO "Docker not running"
82
+    fi
83
+}
84
+
85
+# start_nova_hypervisor - Start any required external services
86
+function start_nova_hypervisor() {
87
+    local docker_pid
88
+    read docker_pid <$DOCKER_PID_FILE
89
+    if [[ -z $docker_pid ]] || ! ps -p $docker_pid | grep [d]ocker; then
90
+        die $LINENO "Docker not running, start the daemon"
91
+    fi
92
+
93
+    # Start the Docker registry container
94
+    docker run -d -p ${DOCKER_REGISTRY_PORT}:5000 \
95
+        -e SETTINGS_FLAVOR=openstack -e OS_USERNAME=${OS_USERNAME} \
96
+        -e OS_PASSWORD=${OS_PASSWORD} -e OS_TENANT_NAME=${OS_TENANT_NAME} \
97
+        -e OS_GLANCE_URL="${SERVICE_PROTOCOL}://${GLANCE_HOSTPORT}" \
98
+        -e OS_AUTH_URL=${OS_AUTH_URL} \
99
+        $DOCKER_REGISTRY_IMAGE_NAME ./docker-registry/run.sh
100
+
101
+    echo "Waiting for docker registry to start..."
102
+    DOCKER_REGISTRY=${SERVICE_HOST}:${DOCKER_REGISTRY_PORT}
103
+    if ! timeout $SERVICE_TIMEOUT sh -c "while ! curl -s $DOCKER_REGISTRY; do sleep 1; done"; then
104
+        die $LINENO "docker-registry did not start"
105
+    fi
106
+
107
+    # Tag image if not already tagged
108
+    if ! docker images | grep $DOCKER_REPOSITORY_NAME; then
109
+        docker tag $DOCKER_IMAGE_NAME $DOCKER_REPOSITORY_NAME
110
+    fi
111
+
112
+    # Make sure we copied the image in Glance
113
+    DOCKER_IMAGE=$(glance image-list | egrep " $DOCKER_IMAGE_NAME ")
114
+    if ! is_set DOCKER_IMAGE ; then
115
+        docker push $DOCKER_REPOSITORY_NAME
116
+    fi
117
+}
118
+
119
+# stop_nova_hypervisor - Stop any external services
120
+function stop_nova_hypervisor() {
121
+    # Stop the docker registry container
122
+    docker kill $(docker ps | grep docker-registry | cut -d' ' -f1)
123
+}
124
+
125
+
126
+# Restore xtrace
127
+$MY_XTRACE
128
+
129
+# Local variables:
130
+# mode: shell-script
131
+# End:
... ...
@@ -319,6 +319,13 @@ source $TOP_DIR/lib/neutron
319 319
 source $TOP_DIR/lib/baremetal
320 320
 source $TOP_DIR/lib/ldap
321 321
 
322
+# Look for Nova hypervisor plugin
323
+NOVA_PLUGINS=$TOP_DIR/lib/nova_plugins
324
+if is_service_enabled nova && [[ -r $NOVA_PLUGINS/hypervisor-$VIRT_DRIVER ]]; then
325
+    # Load plugin
326
+    source $NOVA_PLUGINS/hypervisor-$VIRT_DRIVER
327
+fi
328
+
322 329
 # Set the destination directories for other OpenStack projects
323 330
 OPENSTACKCLIENT_DIR=$DEST/python-openstackclient
324 331
 
... ...
@@ -1013,6 +1020,10 @@ if is_service_enabled cinder; then
1013 1013
     init_cinder
1014 1014
 fi
1015 1015
 
1016
+
1017
+# Compute Service
1018
+# ---------------
1019
+
1016 1020
 if is_service_enabled nova; then
1017 1021
     echo_summary "Configuring Nova"
1018 1022
     # Rebuild the config file from scratch
... ...
@@ -1027,10 +1038,15 @@ if is_service_enabled nova; then
1027 1027
     fi
1028 1028
 
1029 1029
 
1030
+    if [[ -r $NOVA_PLUGINS/hypervisor-$VIRT_DRIVER ]]; then
1031
+        # Configure hypervisor plugin
1032
+        configure_nova_hypervisor
1033
+
1034
+
1030 1035
     # XenServer
1031 1036
     # ---------
1032 1037
 
1033
-    if [ "$VIRT_DRIVER" = 'xenserver' ]; then
1038
+    elif [ "$VIRT_DRIVER" = 'xenserver' ]; then
1034 1039
         echo_summary "Using XenServer virtualization driver"
1035 1040
         if [ -z "$XENAPI_CONNECTION_URL" ]; then
1036 1041
             die $LINENO "XENAPI_CONNECTION_URL is not specified"
1037 1042
new file mode 100644
... ...
@@ -0,0 +1,13 @@
0
+# DevStack on Docker
1
+
2
+Using Docker as Nova's hypervisor requries two steps:
3
+
4
+* Configure DevStack by adding the following to `localrc`::
5
+
6
+    VIRT_DRIVER=docker
7
+
8
+* Download and install the Docker service and images::
9
+
10
+    tools/docker/install_docker.sh
11
+
12
+After this, `stack.sh` should run as normal.
0 13
new file mode 100755
... ...
@@ -0,0 +1,75 @@
0
+#!/usr/bin/env bash
1
+
2
+# **install_docker.sh** - Do the initial Docker installation and configuration
3
+
4
+# install_docker.sh
5
+#
6
+# Install docker package and images
7
+# * downloads a base busybox image and a glance registry image if necessary
8
+# * install the images in Docker's image cache
9
+
10
+
11
+# Keep track of the current directory
12
+SCRIPT_DIR=$(cd $(dirname "$0") && pwd)
13
+TOP_DIR=$(cd $SCRIPT_DIR/../..; pwd)
14
+
15
+# Import common functions
16
+source $TOP_DIR/functions
17
+
18
+# Load local configuration
19
+source $TOP_DIR/stackrc
20
+
21
+FILES=$TOP_DIR/files
22
+
23
+# Get our defaults
24
+source $TOP_DIR/lib/nova_plugins/hypervisor-docker
25
+
26
+SERVICE_TIMEOUT=${SERVICE_TIMEOUT:-60}
27
+
28
+
29
+# Install Docker Service
30
+# ======================
31
+
32
+# Stop the auto-repo updates and do it when required here
33
+NO_UPDATE_REPOS=True
34
+
35
+# Set up home repo
36
+curl https://get.docker.io/gpg | sudo apt-key add -
37
+install_package python-software-properties && \
38
+    sudo sh -c "echo deb $DOCKER_APT_REPO docker main > /etc/apt/sources.list.d/docker.list"
39
+apt_get update
40
+install_package --force-yes lxc-docker=${DOCKER_PACKAGE_VERSION}
41
+
42
+# Start the daemon - restart just in case the package ever auto-starts...
43
+restart_service docker
44
+
45
+echo "Waiting for docker daemon to start..."
46
+DOCKER_GROUP=$(groups | cut -d' ' -f1)
47
+CONFIGURE_CMD="while ! /bin/echo -e 'GET /v1.3/version HTTP/1.0\n\n' | socat - unix-connect:$DOCKER_UNIX_SOCKET | grep -q '200 OK'; do
48
+    # Set the right group on docker unix socket before retrying
49
+    sudo chgrp $DOCKER_GROUP $DOCKER_UNIX_SOCKET
50
+    sudo chmod g+rw $DOCKER_UNIX_SOCKET
51
+    sleep 1
52
+done"
53
+if ! timeout $SERVICE_TIMEOUT sh -c "$CONFIGURE_CMD"; then
54
+    die $LINENO "docker did not start"
55
+fi
56
+
57
+
58
+# Get Docker image
59
+if [[ ! -r $FILES/docker-ut.tar.gz ]]; then
60
+    (cd $FILES; curl -OR $DOCKER_IMAGE)
61
+fi
62
+if [[ ! -r $FILES/docker-ut.tar.gz ]]; then
63
+    die $LINENO "Docker image unavailable"
64
+fi
65
+docker import - $DOCKER_IMAGE_NAME <$FILES/docker-ut.tar.gz
66
+
67
+# Get Docker registry image
68
+if [[ ! -r $FILES/docker-registry.tar.gz ]]; then
69
+    (cd $FILES; curl -OR $DOCKER_REGISTRY_IMAGE)
70
+fi
71
+if [[ ! -r $FILES/docker-registry.tar.gz ]]; then
72
+    die $LINENO "Docker registry image unavailable"
73
+fi
74
+docker import - $DOCKER_REGISTRY_IMAGE_NAME <$FILES/docker-registry.tar.gz
... ...
@@ -65,6 +65,14 @@ if [[ -n "$SCREEN" ]]; then
65 65
     fi
66 66
 fi
67 67
 
68
+# Shut down Nova hypervisor plugins after Nova
69
+NOVA_PLUGINS=$TOP_DIR/lib/nova_plugins
70
+if is_service_enabled nova && [[ -r $NOVA_PLUGINS/hypervisor-$VIRT_DRIVER ]]; then
71
+    # Load plugin
72
+    source $NOVA_PLUGINS/hypervisor-$VIRT_DRIVER
73
+    stop_nova_hypervisor
74
+fi
75
+
68 76
 # Swift runs daemons
69 77
 if is_service_enabled s-proxy; then
70 78
     stop_swift