forked from szweibel/webvm
-
Notifications
You must be signed in to change notification settings - Fork 1
237 lines (203 loc) · 11.2 KB
/
deploy.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
name: Deploy
# Define when the workflow should run
on:
# Allow manual triggering of the workflow from the Actions tab
workflow_dispatch:
# Allow inputs to be passed when manually triggering the workflow from the Actions tab
inputs:
DOCKERFILE_PATH:
type: string
description: 'Path to the Dockerfile'
required: true
default: 'dockerfiles/debian_mini'
IMAGE_SIZE:
type: string
description: 'Image size, 950M max'
required: true
default: '600M'
DEPLOY_TO_GITHUB_PAGES:
type: boolean
description: 'Deploy to Github pages'
required: true
default: true
GITHUB_RELEASE:
type: boolean
description: 'Upload GitHub release'
required: true
default: false
jobs:
guard_clause:
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ github.token }} # As required by the GitHub-CLI
permissions:
actions: 'write' # Required in order to terminate the workflow run.
steps:
- uses: actions/checkout@v3
# Guard clause that cancels the workflow in case of an invalid DOCKERFILE_PATH and/or incorrectly configured Github Pages.
# The main reason for choosing this workaround for aborting the workflow is the fact that it does not display the workflow as successful, which can set false expectations.
- name: DOCKERFILE_PATH.
shell: bash
run: |
# We check whether the Dockerfile_path is valid.
if [ ! -f ${{ github.event.inputs.DOCKERFILE_PATH }} ]; then
echo "::error title=Invalid Dockerfile path::No file found at ${{ github.event.inputs.DOCKERFILE_PATH }}"
echo "terminate=true" >> $GITHUB_ENV
fi
- name: Github Pages config guard clause
if: ${{ github.event.inputs.DEPLOY_TO_GITHUB_PAGES == 'true' }}
run: |
# We use the Github Rest api to get information regarding pages for the Github Repository and store it into a temporary file named "pages_response".
set +e
gh api \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
/repos/${{ github.repository_owner }}/$(basename ${{ github.repository }})/pages > pages_response
# We make sure Github Pages has been enabled for this repository.
if [ "$?" -ne 0 ]; then
echo "::error title=Potential pages configuration error.::Please make sure you have enabled Github pages for the ${{ github.repository }} repository. If already enabled then Github pages might be down"
echo "terminate=true" >> $GITHUB_ENV
fi
set -e
# We make sure the Github pages build & deployment source is set to "workflow" (Github Actions). Instead of a "legacy" (branch).
if [[ "$(jq --compact-output --raw-output .build_type pages_response)" != "workflow" ]]; then
echo "Undefined behaviour, Make sure the Github Pages source is correctly configured in the Github Pages settings."
echo "::error title=Pages configuration error.::Please make sure you have correctly picked \"Github Actions\" as the build and deployment source for the Github Pages."
echo "terminate=true" >> $GITHUB_ENV
fi
rm pages_response
- name: Terminate run if error occurred.
run: |
if [[ $terminate == "true" ]]; then
gh run cancel ${{ github.run_id }}
gh run watch ${{ github.run_id }}
fi
build:
needs: guard_clause # Dependency
runs-on: ubuntu-latest # Image to run the worker on.
env:
TAG: "ext2-webvm-base-image" # Tag of docker image.
IMAGE_SIZE: '${{ github.event.inputs.IMAGE_SIZE }}'
DEPLOY_DIR: /webvm_deploy/ # Path to directory where we host the final image from.
permissions: # Permissions to grant the GITHUB_TOKEN.
contents: write # Required permission to make a github release.
steps:
# Checks-out our repository under $GITHUB_WORKSPACE, so our job can access it
- uses: actions/checkout@v3
# Setting the IMAGE_NAME variable in GITHUB_ENV to <Dockerfile name>_<date>_<run_id>.ext2.
- name: Generate the image_name.
id: image_name_gen
run: |
echo "IMAGE_NAME=$(basename ${{ github.event.inputs.DOCKERFILE_PATH }})_$(date +%Y%m%d)_${{ github.run_id }}.ext2" >> $GITHUB_ENV
# Create directory to host the image from.
- run: sudo mkdir -p $DEPLOY_DIR
# Build the i386 Dockerfile image.
- run: docker build . --tag $TAG --file ${{ github.event.inputs.DOCKERFILE_PATH }} --platform=i386
# Run the docker image so that we can export the container.
# Run the Docker container with the Google Public DNS nameservers: 8.8.8.8, 8.8.4.4
- run: |
docker run --dns 8.8.8.8 --dns 8.8.4.4 -d $TAG
echo "CONTAINER_ID=$(sudo docker ps -aq)" >> $GITHUB_ENV
# We extract the CMD, we first need to figure whether the Dockerfile uses CMD or an Entrypoint.
- name: Extracting CMD / Entrypoint and args
shell: bash
run: |
cmd=$(sudo docker inspect --format='{{json .Config.Cmd}}' $CONTAINER_ID)
entrypoint=$(sudo docker inspect --format='{{json .Config.Entrypoint}}' $CONTAINER_ID)
if [[ $entrypoint != "null" && $cmd != "null" ]]; then
echo "CMD=$( sudo docker inspect $CONTAINER_ID | jq --compact-output '.[0].Config.Entrypoint' )" >> $GITHUB_ENV
echo "ARGS=$( sudo docker inspect $CONTAINER_ID | jq --compact-output '.[0].Config.Cmd' )" >> $GITHUB_ENV
elif [[ $cmd != "null" ]]; then
echo "CMD=$( sudo docker inspect $CONTAINER_ID | jq --compact-output '.[0].Config.Cmd[:1]' )" >> $GITHUB_ENV
echo "ARGS=$( sudo docker inspect $CONTAINER_ID | jq --compact-output '.[0].Config.Cmd[1:]' )" >> $GITHUB_ENV
else
echo "CMD=$( sudo docker inspect $CONTAINER_ID | jq --compact-output '.[0].Config.Entrypoint[:1]' )" >> $GITHUB_ENV
echo "ARGS=$( sudo docker inspect $CONTAINER_ID | jq --compact-output '.[0].Config.Entrypoint[1:]' )" >> $GITHUB_ENV
fi
# We extract the ENV, CMD/Entrypoint and cwd from the Docker container with docker inspect.
- name: Extracting env, args and cwd.
shell: bash
run: |
echo "ENV=$( sudo docker inspect $CONTAINER_ID | jq --compact-output '.[0].Config.Env' )" >> $GITHUB_ENV
echo "CWD=$( sudo docker inspect $CONTAINER_ID | jq --compact-output '.[0].Config.WorkingDir' )" >> $GITHUB_ENV
# We create and mount the base ext2 image to extract the Docker container's filesystem its contents into.
- name: Create ext2 image.
run: |
# Preallocate space for the ext2 image
sudo fallocate -l $IMAGE_SIZE ${IMAGE_NAME}
# Format to ext2 linux kernel revision 0
sudo mkfs.ext2 -r 0 ${IMAGE_NAME}
# Mount the ext2 image to modify it
sudo mount -o loop -t ext2 ${IMAGE_NAME} /mnt/
# We opt for 'docker cp --archive' over 'docker save' since our focus is solely on the end product rather than individual layers and metadata.
# However, it's important to note that despite being specified in the documentation, the '--archive' flag does not currently preserve uid/gid information when copying files from the container to the host machine.
# Another compelling reason to use 'docker cp' is that it preserves resolv.conf.
- name: Export and unpack container filesystem contents into mounted ext2 image.
run: |
sudo docker cp -a ${CONTAINER_ID}:/ /mnt/
sudo umount /mnt/
# Result is an ext2 image for webvm.
# Move required files for gh-pages deployment to the deployment directory $DEPLOY_DIR.
- run: sudo mv assets examples xterm favicon.ico index.html login.html network.js scrollbar.css serviceWorker.js tower.ico $DEPLOY_DIR
# The .txt suffix enabled HTTP compression for free
- name: Generate image split chunks and .meta file
run: |
sudo split ${{ env.IMAGE_NAME }} ${{ env.DEPLOY_DIR }}/${{ env.IMAGE_NAME }}.c -a 6 -b 128k -x --additional-suffix=.txt
sudo bash -c "stat -c%s ${{ env.IMAGE_NAME }} > ${{ env.DEPLOY_DIR }}/${{ env.IMAGE_NAME }}.meta"
# This step updates the default index.html file by performing the following actions:
# 1. Replaces all occurrences of IMAGE_URL with the URL to the image.
# 2. Replaces all occurrences of DEVICE_TYPE to bytes.
# 3. Replace CMD with the Dockerfile entry command.
# 4. Replace args with the Dockerfile CMD / Entrypoint args.
# 5. Replace ENV with the container's environment values.
- name: Adjust index.html
run: |
sudo sed -i 's#IMAGE_URL#"${{ env.IMAGE_NAME }}"#g' ${{ env.DEPLOY_DIR }}index.html
sudo sed -i 's#DEVICE_TYPE#"split"#g' ${{ env.DEPLOY_DIR }}index.html
sudo sed -i 's#CMD#${{ env.CMD }}#g' ${{ env.DEPLOY_DIR }}index.html
sudo sed -i 's#ARGS#${{ env.ARGS }}#g' ${{ env.DEPLOY_DIR }}index.html
sudo sed -i 's#ENV#${{ env.ENV }}#g' ${{ env.DEPLOY_DIR }}index.html
sudo sed -i 's#CWD#${{ env.CWD }}#g' ${{ env.DEPLOY_DIR }}index.html
# We generate index.list files for our httpfs to function properly.
- name: make index.list
shell: bash
run: |
find $DEPLOY_DIR -type d | while read -r dir;
do
index_list="$dir/index.list";
sudo rm -f "$index_list";
sudo ls "$dir" | sudo tee "$index_list" > /dev/null;
sudo chmod +rw "$index_list";
sudo echo "created $index_list";
done
# Create a gh-pages artifact in order to deploy to gh-pages.
- name: Upload GitHub Pages artifact
uses: actions/upload-pages-artifact@v2
with:
# Path of the directory containing the static assets for our gh pages deployment.
path: ${{ env.DEPLOY_DIR }} # optional, default is _site/
- name: github release # To upload our final ext2 image as a github release.
if: ${{ github.event.inputs.GITHUB_RELEASE == 'true' }}
uses: softprops/action-gh-release@v0.1.15
with:
target_commitish: ${{ github.sha }} # Last commit on the GITHUB_REF branch or tag
tag_name: ext2_image
fail_on_unmatched_files: 'true' # Fail in case of no matches with the file(s) glob(s).
files: | # Assets to upload as release.
${{ env.IMAGE_NAME }}
deploy_to_github_pages: # Job that deploys the github-pages artifact to github-pages.
if: ${{ github.event.inputs.DEPLOY_TO_GITHUB_PAGES == 'true' }}
needs: build
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
# Grant GITHUB_TOKEN the permissions required to make a Pages deployment
permissions:
pages: write # to deploy to Pages
id-token: write # to verify the deployment originates from an appropriate source
runs-on: ubuntu-latest
steps:
# Deployment to github pages
- name: Deploy GitHub Pages site
id: deployment
uses: actions/deploy-pages@v3