Skip to content

Commit b5aadb4

Browse files
authored
Merge pull request #71 from AdtSri413/feature/Shawn-Malthus/PROJ-503/Deploying-the-web-application
Added docker deployment code
2 parents 09c9d14 + 76a2837 commit b5aadb4

File tree

9 files changed

+263
-4
lines changed

9 files changed

+263
-4
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,5 @@ dmypy.json
127127

128128
# Pyre type checker
129129
.pyre/
130+
db.sqlite
131+
mysql_data

Dockerfile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
FROM python:3.8-slim
2+
RUN mkdir /app
3+
WORKDIR /app
4+
ADD requirements.txt /app
5+
RUN pip3 install -r requirements.txt
6+
ADD . /app
7+
ADD wait-for-it.sh /app
8+
RUN chmod +x /app/wait-for-it.sh
9+
EXPOSE 8081

README.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,20 @@ cd CISC327-Project
1212
pytest -s qbnb_test
1313

1414
# To run the development server:
15-
python3 -m qbnb
15+
python3 -m qbnb
16+
17+
# To run the dockerised application
18+
1. Ensure docker is installed on your laptop
19+
2. pull the latest code from github (Ensure that docker-compose is in the file)
20+
3. run command “docker pull paynwahs/queens_cmpe327_project:v1” on terminal. This will pull the image docker hub onto your local machine. Run “docker image list” to ensure the image is pulled correctly
21+
4. run command “docker-compose up” to start up docker-compose which will create and start up the following containers:
22+
1. `qbnb-web`: (web-option) Flask web application (including frontend and backend, in reality people like to further break backend into different independent services)
23+
2. `qbnb-db` : MySQL database
24+
3. `phpmyadmin` : Web interface for MySQL These services are all defined in our `docker-compose.yml` file. It also defines some resources:
25+
4. `qbnb-site` : the network connects everything
26+
5. Access the following website from the ports
27+
1. qbnb-web : 127.0.0.1:8081
28+
2. qbnb-db web interface (phpadmin container) : 127.0.0.1:8082
29+
1. server: qbnb-db
30+
2. username: root
31+
3. password: root

db_init.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
CREATE DATABASE IF NOT EXISTS qa327;

docker-compose.yml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
version: "2"
2+
services:
3+
qbnb-web:
4+
image: paynwahs/queens_cmpe327_project:v1
5+
depends_on:
6+
- qbnb-db
7+
links:
8+
- qbnb-db
9+
ports:
10+
- "8081:8081"
11+
environment:
12+
- db_string=mysql+pymysql://root:root@qbnb-db/qa327
13+
command: ["./wait-for-it.sh", "qbnb-db:3306", "--strict" , "--timeout=300", "--", "python", "-m", "qbnb"]
14+
networks:
15+
- qbnb-site
16+
17+
qbnb-db:
18+
platform: linux/x86_64
19+
image: mysql:5.7
20+
environment:
21+
MYSQL_ROOT_PASSWORD: root
22+
command: --init-file /data/application/init.sql
23+
volumes:
24+
- ./mysql_data:/var/lib/mysql
25+
- ./db_init.sql:/data/application/init.sql
26+
networks:
27+
- qbnb-site
28+
29+
phpmyadmin:
30+
image: phpmyadmin/phpmyadmin
31+
depends_on:
32+
- qbnb-db
33+
environment:
34+
PMA_HOST: qbnb-db
35+
PMA_ARBITRARY: 1
36+
restart: always
37+
ports:
38+
- 8082:80
39+
networks:
40+
- qbnb-site
41+
42+
networks:
43+
qbnb-site:
44+

qbnb/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@
1414
)
1515

1616
app = Flask(__name__)
17-
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///../db.sqlite'
17+
db_string = os.getenv('db_string')
18+
if db_string:
19+
app.config['SQLALCHEMY_DATABASE_URI'] = db_string
20+
else:
21+
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///../db.sqlite'
1822
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
1923
app.config['SECRET_KEY'] = '69cae04b04756f65eabcd2c5a11c8c24'
2024
app.app_context().push()

qbnb/__main__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@
99
FLASK_PORT = 8081
1010

1111
if __name__ == "__main__":
12-
app.run(debug=True, port=FLASK_PORT)
12+
app.run(debug=True, port=FLASK_PORT, host='0.0.0.0')

requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ Flask-SQLAlchemy
33
pytest
44
flake8
55
email_validator
6-
seleniumbase
6+
seleniumbase
7+
pymysql

wait-for-it.sh

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
#!/usr/bin/env bash
2+
# Use this script to test if a given TCP host/port are available
3+
4+
WAITFORIT_cmdname=${0##*/}
5+
6+
echoerr() { if [[ $WAITFORIT_QUIET -ne 1 ]]; then echo "$@" 1>&2; fi }
7+
8+
usage()
9+
{
10+
cat << USAGE >&2
11+
Usage:
12+
$WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args]
13+
-h HOST | --host=HOST Host or IP under test
14+
-p PORT | --port=PORT TCP port under test
15+
Alternatively, you specify the host and port as host:port
16+
-s | --strict Only execute subcommand if the test succeeds
17+
-q | --quiet Don't output any status messages
18+
-t TIMEOUT | --timeout=TIMEOUT
19+
Timeout in seconds, zero for no timeout
20+
-- COMMAND ARGS Execute command with args after the test finishes
21+
USAGE
22+
exit 1
23+
}
24+
25+
wait_for()
26+
{
27+
if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
28+
echoerr "$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
29+
else
30+
echoerr "$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout"
31+
fi
32+
WAITFORIT_start_ts=$(date +%s)
33+
while :
34+
do
35+
if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then
36+
nc -z $WAITFORIT_HOST $WAITFORIT_PORT
37+
WAITFORIT_result=$?
38+
else
39+
(echo -n > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1
40+
WAITFORIT_result=$?
41+
fi
42+
if [[ $WAITFORIT_result -eq 0 ]]; then
43+
WAITFORIT_end_ts=$(date +%s)
44+
echoerr "$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds"
45+
break
46+
fi
47+
sleep 1
48+
done
49+
return $WAITFORIT_result
50+
}
51+
52+
wait_for_wrapper()
53+
{
54+
# In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692
55+
if [[ $WAITFORIT_QUIET -eq 1 ]]; then
56+
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
57+
else
58+
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
59+
fi
60+
WAITFORIT_PID=$!
61+
trap "kill -INT -$WAITFORIT_PID" INT
62+
wait $WAITFORIT_PID
63+
WAITFORIT_RESULT=$?
64+
if [[ $WAITFORIT_RESULT -ne 0 ]]; then
65+
echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
66+
fi
67+
return $WAITFORIT_RESULT
68+
}
69+
70+
# process arguments
71+
while [[ $# -gt 0 ]]
72+
do
73+
case "$1" in
74+
*:* )
75+
WAITFORIT_hostport=(${1//:/ })
76+
WAITFORIT_HOST=${WAITFORIT_hostport[0]}
77+
WAITFORIT_PORT=${WAITFORIT_hostport[1]}
78+
shift 1
79+
;;
80+
--child)
81+
WAITFORIT_CHILD=1
82+
shift 1
83+
;;
84+
-q | --quiet)
85+
WAITFORIT_QUIET=1
86+
shift 1
87+
;;
88+
-s | --strict)
89+
WAITFORIT_STRICT=1
90+
shift 1
91+
;;
92+
-h)
93+
WAITFORIT_HOST="$2"
94+
if [[ $WAITFORIT_HOST == "" ]]; then break; fi
95+
shift 2
96+
;;
97+
--host=*)
98+
WAITFORIT_HOST="${1#*=}"
99+
shift 1
100+
;;
101+
-p)
102+
WAITFORIT_PORT="$2"
103+
if [[ $WAITFORIT_PORT == "" ]]; then break; fi
104+
shift 2
105+
;;
106+
--port=*)
107+
WAITFORIT_PORT="${1#*=}"
108+
shift 1
109+
;;
110+
-t)
111+
WAITFORIT_TIMEOUT="$2"
112+
if [[ $WAITFORIT_TIMEOUT == "" ]]; then break; fi
113+
shift 2
114+
;;
115+
--timeout=*)
116+
WAITFORIT_TIMEOUT="${1#*=}"
117+
shift 1
118+
;;
119+
--)
120+
shift
121+
WAITFORIT_CLI=("$@")
122+
break
123+
;;
124+
--help)
125+
usage
126+
;;
127+
*)
128+
echoerr "Unknown argument: $1"
129+
usage
130+
;;
131+
esac
132+
done
133+
134+
if [[ "$WAITFORIT_HOST" == "" || "$WAITFORIT_PORT" == "" ]]; then
135+
echoerr "Error: you need to provide a host and port to test."
136+
usage
137+
fi
138+
139+
WAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15}
140+
WAITFORIT_STRICT=${WAITFORIT_STRICT:-0}
141+
WAITFORIT_CHILD=${WAITFORIT_CHILD:-0}
142+
WAITFORIT_QUIET=${WAITFORIT_QUIET:-0}
143+
144+
# Check to see if timeout is from busybox?
145+
WAITFORIT_TIMEOUT_PATH=$(type -p timeout)
146+
WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH)
147+
148+
WAITFORIT_BUSYTIMEFLAG=""
149+
if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then
150+
WAITFORIT_ISBUSY=1
151+
# Check if busybox timeout uses -t flag
152+
# (recent Alpine versions don't support -t anymore)
153+
if timeout &>/dev/stdout | grep -q -e '-t '; then
154+
WAITFORIT_BUSYTIMEFLAG="-t"
155+
fi
156+
else
157+
WAITFORIT_ISBUSY=0
158+
fi
159+
160+
if [[ $WAITFORIT_CHILD -gt 0 ]]; then
161+
wait_for
162+
WAITFORIT_RESULT=$?
163+
exit $WAITFORIT_RESULT
164+
else
165+
if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
166+
wait_for_wrapper
167+
WAITFORIT_RESULT=$?
168+
else
169+
wait_for
170+
WAITFORIT_RESULT=$?
171+
fi
172+
fi
173+
174+
if [[ $WAITFORIT_CLI != "" ]]; then
175+
if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then
176+
echoerr "$WAITFORIT_cmdname: strict mode, refusing to execute subprocess"
177+
exit $WAITFORIT_RESULT
178+
fi
179+
exec "${WAITFORIT_CLI[@]}"
180+
else
181+
exit $WAITFORIT_RESULT
182+
fi

0 commit comments

Comments
 (0)