diff --git a/2.7/Dockerfile b/2.7/Dockerfile
index 642c40a..7a8dbd2 100644
--- a/2.7/Dockerfile
+++ b/2.7/Dockerfile
@@ -1,4 +1,4 @@
-FROM mcr.microsoft.com/oryx/python:2.7-20190730.1
+FROM mcr.microsoft.com/oryx/python:2.7-20191018.1
LABEL maintainer="appsvc-images@microsoft.com"
# Web Site Home
@@ -13,6 +13,10 @@ RUN apt-get update \
wget \
# build-essential \
tcptraceroute \
+ net-tools \
+ dnsutils \
+ tcpdump \
+ iproute2 \
&& pip install --upgrade pip \
&& pip install gunicorn \
&& pip install virtualenv \
@@ -28,7 +32,7 @@ ENV SSH_PORT 2222
# setup SSH
RUN mkdir -p /home/LogFiles \
&& echo "root:Docker!" | chpasswd \
- && echo "cd /home" >> /etc/bash.bashrc
+ && echo "cd /home" >> /root/.bashrc
COPY sshd_config /etc/ssh/
RUN mkdir -p /opt/startup
@@ -37,6 +41,7 @@ COPY init_container.sh /opt/startup/init_container.sh
# setup default site
RUN mkdir /opt/defaultsite
COPY hostingstart.html /opt/defaultsite
+COPY hostingstart_dep.html /opt/defaultsite
COPY application.py /opt/defaultsite
# configure startup
diff --git a/2.7/application.py b/2.7/application.py
index ae7b9e5..cf9c45a 100644
--- a/2.7/application.py
+++ b/2.7/application.py
@@ -1,6 +1,10 @@
from flask import Flask
+import os
app = Flask(__name__, static_folder='/opt/defaultsite')
@app.route('/')
def root():
- return app.send_static_file('hostingstart.html')
+ if os.path.isdir('/home/site/deployments') and len(os.walk('/home/site/deployments')[1]) > 1:
+ return app.send_static_file('hostingstart_dep.html')
+ else:
+ return app.send_static_file('hostingstart.html')
diff --git a/2.7/hostingstart_dep.html b/2.7/hostingstart_dep.html
new file mode 100644
index 0000000..51d61bb
--- /dev/null
+++ b/2.7/hostingstart_dep.html
@@ -0,0 +1 @@
+
Microsoft Azure App Service - Welcome
diff --git a/2.7/init_container.sh b/2.7/init_container.sh
index d69413e..e8da03a 100644
--- a/2.7/init_container.sh
+++ b/2.7/init_container.sh
@@ -54,6 +54,18 @@ else
fi
fi
+debugArgs=""
+if [ "$APPSVC_REMOTE_DEBUGGING" == "TRUE" ]; then
+ echo "App will launch in debug mode"
+ debugArgs="-debugAdapter ptvsd -debugPort $APPSVC_TUNNEL_PORT"
+
+ if [ "$APPSVC_REMOTE_DEBUGGING_BREAK" == "TRUE" ]; then
+ debugArgs+=" -debugWait"
+ fi
+
+ oryxArgs="$debugArgs $oryxArgs"
+fi
+
echo "Launching oryx with: $oryxArgs"
#invoke oryx to generate startup script
eval "oryx $oryxArgs"
diff --git a/3.6/Dockerfile b/3.6/Dockerfile
index 51bd687..87d89d8 100644
--- a/3.6/Dockerfile
+++ b/3.6/Dockerfile
@@ -1,4 +1,4 @@
-FROM mcr.microsoft.com/oryx/python:3.6-20190730.1
+FROM mcr.microsoft.com/oryx/python:3.6-20191018.1
LABEL maintainer="appsvc-images@microsoft.com"
# Web Site Home
@@ -12,6 +12,10 @@ RUN apt-get update \
curl \
wget \
tcptraceroute \
+ net-tools \
+ dnsutils \
+ tcpdump \
+ iproute2 \
&& pip install --upgrade pip \
&& pip install subprocess32 \
&& pip install gunicorn \
@@ -27,7 +31,7 @@ ENV SSH_PORT 2222
# setup SSH
RUN mkdir -p /home/LogFiles \
&& echo "root:Docker!" | chpasswd \
- && echo "cd /home" >> /etc/bash.bashrc
+ && echo "cd /home" >> /root/.bashrc
COPY sshd_config /etc/ssh/
RUN mkdir -p /opt/startup
@@ -36,6 +40,7 @@ COPY init_container.sh /opt/startup/init_container.sh
# setup default site
RUN mkdir /opt/defaultsite
COPY hostingstart.html /opt/defaultsite
+COPY hostingstart_dep.html /opt/defaultsite
COPY application.py /opt/defaultsite
# configure startup
diff --git a/3.6/application.py b/3.6/application.py
index ae7b9e5..0737e26 100644
--- a/3.6/application.py
+++ b/3.6/application.py
@@ -1,6 +1,10 @@
from flask import Flask
+import os
app = Flask(__name__, static_folder='/opt/defaultsite')
@app.route('/')
def root():
- return app.send_static_file('hostingstart.html')
+ if os.path.isdir('/home/site/deployments') and len(next(os.walk('/home/site/deployments'))[1]) > 1:
+ return app.send_static_file('hostingstart_dep.html')
+ else:
+ return app.send_static_file('hostingstart.html')
diff --git a/3.6/hostingstart_dep.html b/3.6/hostingstart_dep.html
new file mode 100644
index 0000000..51d61bb
--- /dev/null
+++ b/3.6/hostingstart_dep.html
@@ -0,0 +1 @@
+ Microsoft Azure App Service - Welcome
diff --git a/3.6/init_container.sh b/3.6/init_container.sh
index 9687cfb..fb9028a 100644
--- a/3.6/init_container.sh
+++ b/3.6/init_container.sh
@@ -54,6 +54,18 @@ else
fi
fi
+debugArgs=""
+if [ "$APPSVC_REMOTE_DEBUGGING" == "TRUE" ]; then
+ echo "App will launch in debug mode"
+ debugArgs="-debugAdapter ptvsd -debugPort $APPSVC_TUNNEL_PORT"
+
+ if [ "$APPSVC_REMOTE_DEBUGGING_BREAK" == "TRUE" ]; then
+ debugArgs+=" -debugWait"
+ fi
+
+ oryxArgs="$debugArgs $oryxArgs"
+fi
+
echo "Launching oryx with: $oryxArgs"
#invoke oryx to generate startup script
eval "oryx $oryxArgs"
diff --git a/3.7/Dockerfile b/3.7/Dockerfile
index 7c5e091..79b38a9 100644
--- a/3.7/Dockerfile
+++ b/3.7/Dockerfile
@@ -1,4 +1,4 @@
-FROM mcr.microsoft.com/oryx/python:3.7-20190730.1
+FROM mcr.microsoft.com/oryx/python:3.7-20191018.1
LABEL maintainer="appsvc-images@microsoft.com"
# Web Site Home
@@ -12,6 +12,10 @@ RUN apt-get update \
curl \
wget \
tcptraceroute \
+ net-tools \
+ dnsutils \
+ tcpdump \
+ iproute2 \
&& pip install --upgrade pip \
&& pip install subprocess32 \
&& pip install gunicorn \
@@ -27,8 +31,8 @@ ENV SSH_PORT 2222
# setup SSH
RUN mkdir -p /home/LogFiles \
&& echo "root:Docker!" | chpasswd \
- && echo "cd /home" >> /etc/bash.bashrc
-
+ && echo "cd /home" >> /root/.bashrc
+
COPY sshd_config /etc/ssh/
RUN mkdir -p /opt/startup
COPY init_container.sh /opt/startup/init_container.sh
@@ -36,6 +40,7 @@ COPY init_container.sh /opt/startup/init_container.sh
# setup default site
RUN mkdir /opt/defaultsite
COPY hostingstart.html /opt/defaultsite
+COPY hostingstart_dep.html /opt/defaultsite
COPY application.py /opt/defaultsite
# configure startup
diff --git a/3.7/application.py b/3.7/application.py
index ae7b9e5..0737e26 100644
--- a/3.7/application.py
+++ b/3.7/application.py
@@ -1,6 +1,10 @@
from flask import Flask
+import os
app = Flask(__name__, static_folder='/opt/defaultsite')
@app.route('/')
def root():
- return app.send_static_file('hostingstart.html')
+ if os.path.isdir('/home/site/deployments') and len(next(os.walk('/home/site/deployments'))[1]) > 1:
+ return app.send_static_file('hostingstart_dep.html')
+ else:
+ return app.send_static_file('hostingstart.html')
diff --git a/3.7/hostingstart_dep.html b/3.7/hostingstart_dep.html
new file mode 100644
index 0000000..51d61bb
--- /dev/null
+++ b/3.7/hostingstart_dep.html
@@ -0,0 +1 @@
+ Microsoft Azure App Service - Welcome
diff --git a/3.7/init_container.sh b/3.7/init_container.sh
index 2f0d9e1..62f9816 100644
--- a/3.7/init_container.sh
+++ b/3.7/init_container.sh
@@ -25,7 +25,6 @@ eval $(printenv | sed -n "s/^\([^=]\+\)=\(.*\)$/export \1=\2/p" | sed 's/"/\\\"/
echo "$@" > /opt/startup/startupCommand
chmod 755 /opt/startup/startupCommand
-#oryx startup script generator
oryxArgs="-appPath /home/site/wwwroot -output /opt/startup/startup.sh -virtualEnvName antenv -defaultApp /opt/defaultsite -bindPort $PORT"
if [ $# -eq 0 ]; then
echo 'App Command Line not configured, will attempt auto-detect'
@@ -55,6 +54,18 @@ else
fi
fi
+debugArgs=""
+if [ "$APPSVC_REMOTE_DEBUGGING" == "TRUE" ]; then
+ echo "App will launch in debug mode"
+ debugArgs="-debugAdapter ptvsd -debugPort $APPSVC_TUNNEL_PORT"
+
+ if [ "$APPSVC_REMOTE_DEBUGGING_BREAK" == "TRUE" ]; then
+ debugArgs+=" -debugWait"
+ fi
+
+ oryxArgs="$debugArgs $oryxArgs"
+fi
+
echo "Launching oryx with: $oryxArgs"
#invoke oryx to generate startup script
eval "oryx $oryxArgs"
diff --git a/3.8/Dockerfile b/3.8/Dockerfile
new file mode 100644
index 0000000..09fd6fb
--- /dev/null
+++ b/3.8/Dockerfile
@@ -0,0 +1,50 @@
+FROM mcr.microsoft.com/oryx/python:3.8-20191018.1
+LABEL maintainer="appsvc-images@microsoft.com"
+
+# Web Site Home
+ENV HOME_SITE "/home/site/wwwroot"
+
+#Install system dependencies
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends \
+ openssh-server \
+ vim \
+ curl \
+ wget \
+ tcptraceroute \
+ net-tools \
+ dnsutils \
+ tcpdump \
+ iproute2 \
+ && pip install --upgrade pip \
+ && pip install subprocess32 \
+ && pip install gunicorn \
+ && pip install virtualenv \
+ && pip install flask
+
+WORKDIR ${HOME_SITE}
+
+EXPOSE 8000
+ENV PORT 8000
+ENV SSH_PORT 2222
+
+# setup SSH
+RUN mkdir -p /home/LogFiles \
+ && echo "root:Docker!" | chpasswd \
+ && echo "cd /home" >> /root/.bashrc
+
+COPY sshd_config /etc/ssh/
+RUN mkdir -p /opt/startup
+COPY init_container.sh /opt/startup/init_container.sh
+
+# setup default site
+RUN mkdir /opt/defaultsite
+COPY hostingstart.html /opt/defaultsite
+COPY hostingstart_dep.html /opt/defaultsite
+COPY application.py /opt/defaultsite
+
+# configure startup
+RUN chmod -R 777 /opt/startup
+COPY entrypoint.py /usr/local/bin
+
+ENTRYPOINT ["/opt/startup/init_container.sh"]
diff --git a/3.8/application.py b/3.8/application.py
new file mode 100644
index 0000000..0737e26
--- /dev/null
+++ b/3.8/application.py
@@ -0,0 +1,10 @@
+from flask import Flask
+import os
+app = Flask(__name__, static_folder='/opt/defaultsite')
+
+@app.route('/')
+def root():
+ if os.path.isdir('/home/site/deployments') and len(next(os.walk('/home/site/deployments'))[1]) > 1:
+ return app.send_static_file('hostingstart_dep.html')
+ else:
+ return app.send_static_file('hostingstart.html')
diff --git a/3.8/build.sh b/3.8/build.sh
new file mode 100644
index 0000000..5bfe175
--- /dev/null
+++ b/3.8/build.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+set -x -e
+
+buildnumber=${4-$(date -u +"%y%m%d%H%M")}
+
+docker build --no-cache -t "$1"/python:3.8_"$buildnumber" .
+docker tag "$1"/python:3.7_"$buildnumber" "$1"/python:latest
diff --git a/3.8/entrypoint.py b/3.8/entrypoint.py
new file mode 100644
index 0000000..ca3b5a3
--- /dev/null
+++ b/3.8/entrypoint.py
@@ -0,0 +1,120 @@
+import subprocess
+import os
+
+HOME_SITE="/home/site/wwwroot"
+DEFAULT_SITE="/opt/defaultsite"
+STARTUP_COMMAND_FILE="/opt/startup/startupCommand"
+APPSVC_VIRTUAL_ENV="antenv"
+
+# Temp patch. Remove when Kudu script is available.
+os.environ["PYTHONPATH"] = HOME_SITE + "/antenv/lib/python3.8/site-packages"
+
+def subprocess_cmd(command):
+ print ('executing:')
+ print (command)
+
+ process = subprocess.Popen(command,stdout=subprocess.PIPE, shell=True)
+ proc_stdout = process.communicate()[0].strip()
+ print (proc_stdout.decode("utf-8"))
+
+## Check for custom startup command
+def custom_check():
+ with open(STARTUP_COMMAND_FILE, 'r') as myfile:
+ startupScript = myfile.read().rstrip()
+ if not startupScript:
+ return None
+ else:
+ if ".." not in startupScript:
+ startupFilePath = HOME_SITE + '/' + startupScript
+ print('startup script: ' + startupFilePath)
+ try:
+ startupFile = open(startupFilePath, 'r')
+ print ('identified startup script as a file on disk')
+ startArgs = startupFile.read()
+ print(startArgs)
+ if not startArgs:
+ return None
+ else:
+ return startArgs
+
+ except:
+ # appCommandLine is not a file, assume it is the script to be started bu gunicorn
+ print('startup script is not a file, use it as gunicorn arg')
+ return startupScript
+ else:
+ print('invalid data in startup script, ignoring it.')
+ return None
+
+ return startupScript
+
+## Django check: If 'wsgi.py' is provided, identify as Django.
+def check_django():
+ with os.scandir(HOME_SITE) as siteRoot:
+ for entry in siteRoot:
+ if not entry.name.startswith(APPSVC_VIRTUAL_ENV) and entry.is_dir():
+ with os.scandir(HOME_SITE + '/'+ entry.name) as subFolder:
+ for subEntry in subFolder:
+ if subEntry.name == 'wsgi.py' and subEntry.is_file():
+ print ("found django app")
+ return entry.name + '.wsgi'
+ return None
+
+## Flask check: If 'application.py' is provided or a .py module is present, identify as Flask.
+def check_flask():
+ with os.scandir(HOME_SITE) as siteRoot:
+ for entry in siteRoot:
+ if entry.is_file():
+ if (entry.name == 'application.py'):
+ print("found flask app")
+ return "application:app"
+ else:
+ if (entry.name == 'app.py'):
+ print("found flask app")
+ return "app:app"
+
+ return None
+
+def start_server():
+
+ cmd = custom_check()
+ if cmd is not None:
+ print('custom startup found: ' + cmd);
+ subprocess_cmd('. antenv/bin/activate')
+ if 'python' in cmd:
+ subprocess_cmd(cmd)
+
+ elif 'gunicorn' in cmd:
+ subprocess_cmd(cmd)
+
+ else:
+ subprocess_cmd(
+ 'GUNICORN_CMD_ARGS="--bind=0.0.0.0 --timeout 600" gunicorn ' + cmd
+ )
+ return
+
+ cmd = check_django()
+ if cmd is not None:
+ subprocess_cmd('. antenv/bin/activate')
+ subprocess_cmd(
+ 'GUNICORN_CMD_ARGS="--bind=0.0.0.0 --timeout 600" gunicorn ' + cmd
+ )
+ return
+
+ cmd = check_flask()
+ if cmd is not None:
+ subprocess_cmd('. antenv/bin/activate')
+ subprocess_cmd(
+ 'GUNICORN_CMD_ARGS="--bind=0.0.0.0 --timeout 600" gunicorn ' + cmd
+ )
+ return
+
+ else:
+ print('starting default app')
+ subprocess_cmd(
+ 'GUNICORN_CMD_ARGS="--bind=0.0.0.0 --chdir /opt/defaultsite" gunicorn application:app'
+ )
+ return
+
+subprocess_cmd('python --version')
+subprocess_cmd('pip --version')
+start_server()
diff --git a/3.8/hostingstart.html b/3.8/hostingstart.html
new file mode 100644
index 0000000..5c89769
--- /dev/null
+++ b/3.8/hostingstart.html
@@ -0,0 +1 @@
+Microsoft Azure App Service - Welcome
diff --git a/3.8/hostingstart_dep.html b/3.8/hostingstart_dep.html
new file mode 100644
index 0000000..51d61bb
--- /dev/null
+++ b/3.8/hostingstart_dep.html
@@ -0,0 +1 @@
+ Microsoft Azure App Service - Welcome
diff --git a/3.8/init.py b/3.8/init.py
new file mode 100644
index 0000000..370c93e
--- /dev/null
+++ b/3.8/init.py
@@ -0,0 +1,59 @@
+import subprocess
+import os
+
+HOME_SITE="/home/site/wwwroot"
+DEFAULT_SITE="/opt/defaultsite"
+STARTUP_COMMAND_FILE="/opt/startup/startupCommand"
+APPSVC_VIRTUAL_ENV="antenv"
+
+def subprocess_cmd(command):
+ print ('executing:')
+ print (command)
+
+ process = subprocess.Popen(command,stdout=subprocess.PIPE, shell=True)
+ proc_stdout = process.communicate()[0].strip()
+ print (proc_stdout.decode("utf-8"))
+
+def getStartupArgs():
+ with open(STARTUP_COMMAND_FILE, 'r') as myfile:
+ startupScript = myfile.read().rstrip()
+ if not startupScript:
+ print('App startup command not specified, will use defaults..')
+ return None
+ else:
+ if ".." not in startupScript:
+ startupFilePath = HOME_SITE + '/' + startupScript
+ print('checking for startup script file: ' + startupFilePath)
+ try:
+ startupFile = open(startupFilePath, 'r')
+ print ('identified startup script as a file on disk')
+ startArgs = startupFile.read()
+ print(startArgs)
+ if not startArgs:
+ return None
+ else:
+ return startArgs
+
+ except:
+ # appCommandLine is not a file, assume it is the script to be started bu gunicorn
+ print('startup script is not a file, use it as gunicorn arg')
+ return startupScript
+
+def find_and_launch_entrypoint():
+ if os.path.isdir(HOME_SITE + '/antenv'):
+ print('Executing entrypoint.py script:')
+ subprocess_cmd('python -u /usr/local/bin/entrypoint.py')
+ else:
+ oryxCmd = "oryx -appPath /home/site/wwwroot -output /opt/startup/startup.sh -defaultApp /opt/defaultsite "
+ cmd = getStartupArgs()
+ if cmd is not None:
+ oryxCmd += ' -userStartupCommand ' + '\'' + cmd + '\''
+
+ print('Generating startup command with oryxCmd ' + oryxCmd)
+ subprocess_cmd(oryxCmd)
+ print('Launching oryx-Startup script ')
+ subprocess_cmd('chmod +x /opt/startup/startup.sh')
+ subprocess_cmd('/opt/startup/startup.sh')
+
+subprocess_cmd('python --version')
+find_and_launch_entrypoint()
\ No newline at end of file
diff --git a/3.8/init_container.sh b/3.8/init_container.sh
new file mode 100644
index 0000000..6d466b8
--- /dev/null
+++ b/3.8/init_container.sh
@@ -0,0 +1,76 @@
+#!/usr/bin/env bash
+
+cat >/etc/motd <
+ \/ \/ \/
+
+A P P S E R V I C E O N L I N U X
+
+Documentation: http://aka.ms/webapp-linux
+
+EOL
+cat /etc/motd
+
+sed -i "s/SSH_PORT/$SSH_PORT/g" /etc/ssh/sshd_config
+service ssh start
+
+# Get environment variables to show up in SSH session
+eval $(printenv | sed -n "s/^\([^=]\+\)=\(.*\)$/export \1=\2/p" | sed 's/"/\\\"/g' | sed '/=/s//="/' | sed 's/$/"/' >> /etc/profile)
+
+echo "$@" > /opt/startup/startupCommand
+chmod 755 /opt/startup/startupCommand
+
+oryxArgs='-appPath /home/site/wwwroot -output /opt/startup/startup.sh -virtualEnvName antenv -defaultApp /opt/defaultsite'
+if [ $# -eq 0 ]; then
+ echo 'App Command Line not configured, will attempt auto-detect'
+else
+ echo "Site's appCommandLine: $@"
+ if [ $# -eq 1 ]; then
+ echo "Checking of $1 is a file"
+ if [ -f $1 ]; then
+ echo 'App command line is a file on disk'
+ fileContents=$(head -1 $1)
+ #if the file ends with .sh
+ if [ ${1: -3} == ".sh" ]; then
+ echo 'App command line is a shell script, will execute this script as startup script'
+ chmod +x $1
+ oryxArgs+=" -userStartupCommand $1"
+ else
+ echo "$1 file exists on disk, reading its contents to run as startup arguments"
+ echo "Contents of startupScript: $fileContents"
+ oryxArgs+=" -userStartupCommand '$fileContents'"
+ fi
+ else
+ echo 'App command line is not a file on disk, using it as the startup command.'
+ oryxArgs+=" -userStartupCommand '$1'"
+ fi
+ else
+ oryxArgs+=" -userStartupCommand '$@'"
+ fi
+fi
+
+debugArgs=""
+if [ "$APPSVC_REMOTE_DEBUGGING" == "TRUE" ]; then
+ echo "App will launch in debug mode"
+ debugArgs="-debugAdapter ptvsd -debugPort $APPSVC_TUNNEL_PORT"
+
+ if [ "$APPSVC_REMOTE_DEBUGGING_BREAK" == "TRUE" ]; then
+ debugArgs+=" -debugWait"
+ fi
+
+ oryxArgs="$debugArgs $oryxArgs"
+fi
+
+echo "Launching oryx with: $oryxArgs"
+#invoke oryx to generate startup script
+eval "oryx $oryxArgs"
+chmod +x /opt/startup/startup.sh
+#launch startup script
+/opt/startup/startup.sh
+
+
diff --git a/3.8/sshd_config b/3.8/sshd_config
new file mode 100644
index 0000000..04b53f9
--- /dev/null
+++ b/3.8/sshd_config
@@ -0,0 +1,16 @@
+# This is ssh server systemwide configuration file.
+#
+# /etc/sshd_config
+
+Port SSH_PORT
+ListenAddress 0.0.0.0
+LoginGraceTime 180
+X11Forwarding yes
+Ciphers aes128-cbc,3des-cbc,aes256-cbc,aes128-ctr,aes192-ctr,aes256-ctr
+MACs hmac-sha1,hmac-sha1-96
+StrictModes yes
+SyslogFacility DAEMON
+PasswordAuthentication yes
+PermitEmptyPasswords no
+PermitRootLogin yes
+Subsystem sftp internal-sftp