-
Notifications
You must be signed in to change notification settings - Fork 20
/
action.yaml
202 lines (194 loc) · 7.32 KB
/
action.yaml
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
name: Submit a Testflinger job
description: Submit a job to a Testflinger server
inputs:
job:
description: "Inline contents of a job file (see https://canonical-testflinger.readthedocs-hosted.com/en/latest/reference/job-schema/ for more info)"
required: false
job-path:
description: "Path to a job file (see https://canonical-testflinger.readthedocs-hosted.com/en/latest/reference/job-schema/ for more info)"
required: false
poll:
description: Specify if the submitted job should be tracked to completion
required: false
default: false
dry-run:
description: Specify if the job should really be submitted
required: false
default: false
server:
description: The Testflinger server to use
required: false
default: testflinger.canonical.com
attachments-relative-to:
description: The reference directory for relative attachment paths
required: false
outputs:
id:
description: 'The ID of the submitted job'
value: ${{ steps.submit.outputs.id }}
device-ip:
description: 'The IP of the reserved device (if applicable)'
value: ${{ steps.track-reservation.outputs.ip }}
runs:
using: composite
steps:
- name: Test connection to Testflinger server
shell: bash {0} # allow curl to fail
env:
SERVER: https://${{ inputs.server }}
run: |
echo "::group::Test connection to Testflinger server"
STATUS=$(curl --stderr error.log -Ivw "%{http_code}\n" -o /dev/null $SERVER/jobs)
ERROR=$?
if [ ! $ERROR -eq 0 ]; then
echo "Unable to ping Testflinger server at $SERVER"
cat error.log
exit $ERROR
elif [ ! $STATUS -eq 200 ]; then
echo "Failed server ping at $SERVER, error status: $STATUS"
cat error.log
exit $STATUS
else
echo "Successful server ping at $SERVER, status: $STATUS"
fi
echo "::endgroup::"
- name: Create job file, if required
id: create-job-file
shell: bash
run: |
echo "::group::Create job file (if required)"
if [ -n "${{ inputs.job-path }}" ]; then
# the `$JOB` environment variable points to the job path provided as input
echo "JOB=${{ inputs.job-path }}" >> $GITHUB_ENV
else
# write the inline job text to a file
FILE=${{ github.workspace }}/tmp_job.yaml
# do not ever indent these lines; the here-doc is sensitive to that
cat > $FILE << EOF
${{ inputs.job }}
EOF
if [[ $(cat "$FILE" | wc -w) == 0 ]]; then
echo 'Neither of the `job` or `job-path` inputs have been specified'
exit 1
fi
# the `$JOB` environment variable points to the newly created job file
echo "JOB=$FILE" >> $GITHUB_ENV
fi
echo "::endgroup::"
- name: Display contents of job file (for verification)
shell: bash
run: |
echo "::group::Display job file"
cat "$JOB"
echo "::endgroup::"
- name: Determine if this is a reservation job
id: check-reservation
shell: bash
run: |
echo "::group::Determine if this is a reservation job"
if grep -q "^reserve_data:" $JOB; then
RESERVATION=true
else
RESERVATION=false
fi
echo "reservation=$RESERVATION" | tee -a $GITHUB_OUTPUT
echo "::endgroup::"
- name: Install prerequisites
shell: bash
run: |
echo "::group::Install prerequisites"
sudo snap install testflinger-cli jq
echo "::endgroup::"
- name: Submit job to the Testflinger server
id: submit
if: inputs.dry-run != 'true'
shell: bash
env:
SERVER: https://${{ inputs.server }}
RELATIVE_TO: ${{ inputs.attachments-relative-to }}
run: |
echo "::group::Submit job to the Testflinger server"
if [ -n "$RELATIVE_TO" ]; then
RELATIVE="--attachments-relative-to $RELATIVE_TO"
fi
JOB_ID=$(testflinger --server $SERVER submit --quiet "$RELATIVE" "$JOB")
echo "id=$JOB_ID" >> $GITHUB_OUTPUT
echo "::endgroup::"
echo "::notice::Submitted job $JOB_ID"
- name: Track the status of the job (non-reservation)
if: inputs.poll == 'true' && inputs.dry-run != 'true' && steps.check-reservation.outputs.reservation != 'true'
shell: bash
env:
SERVER: https://${{ inputs.server }}
JOB_ID: ${{ steps.submit.outputs.id }}
run: |
echo "::group::Track the status of job ${{ env.JOB_ID }}"
# poll
PYTHONUNBUFFERED=1 testflinger --server $SERVER poll $JOB_ID
echo "::endgroup::"
echo "::group::Retrieve job results, determine exit status"
# the exit status is the maximum status of the individual test phases
# (excluding the setup and cleanup phases)
EXIT_STATUS=$(\
testflinger --server $SERVER results $JOB_ID \
| jq 'to_entries
| map(
select(
(.key | endswith("_status"))
and .key != "setup_status"
and .key != "cleanup_status"
).value
)
| max'
)
echo "::endgroup::"
echo "::notice::Test exit status: $EXIT_STATUS"
exit $EXIT_STATUS
- name: Track the status of the job (reservation)
id: track-reservation
if: inputs.poll == 'true' && inputs.dry-run != 'true' && steps.check-reservation.outputs.reservation == 'true'
shell: bash
env:
SERVER: https://${{ inputs.server }}
JOB_ID: ${{ steps.submit.outputs.id }}
TERMINATION: "TESTFLINGER SYSTEM RESERVED"
run: |
echo "::group::Track the status of reservation job ${{ env.JOB_ID }}"
# specify file for capturing output and clear it
CAPTURED_OUTPUT=output
> "$CAPTURED_OUTPUT"
# perform one-shot polling until the reserve phase has been reached
# and the captured output contains the TERMINATION string
while true; do
PYTHONUNBUFFERED=1 testflinger --server $SERVER poll --oneshot $JOB_ID | tee -a "$CAPTURED_OUTPUT"
JOB_STATUS="$(testflinger --server $SERVER status $JOB_ID)"
if [ "$JOB_STATUS" = "reserve" ]; then
if grep -q "$TERMINATION" "$CAPTURED_OUTPUT"; then
EXIT_STATUS=0
break
fi
elif [[ "$JOB_STATUS" =~ ^(complete|cancelled)$ ]]; then
EXIT_STATUS=1
break
fi
sleep 10
done
echo "::endgroup::"
echo "::group::Retrieve IP of reserved machine"
DEVICE_IP=$(grep -m 1 "^Now try logging into the machine" "$CAPTURED_OUTPUT" | sed -n "s/.*@\([0-9.]*\).*/\1/p")
[ "$?" -eq 0 ] && DEVICE_IP_FLAG=true
[ -n "$DEVICE_IP_FLAG" ] && echo "ip=$DEVICE_IP" >> $GITHUB_OUTPUT
echo "::endgroup::"
echo "::notice::Reserve exit status: $EXIT_STATUS"
[ -n "$DEVICE_IP_FLAG" ] && echo "::notice::Device IP: $DEVICE_IP"
exit $EXIT_STATUS
- name: Cancel the job if the action is cancelled
if: ${{ cancelled() }}
shell: bash
env:
SERVER: https://${{ inputs.server }}
JOB_ID: ${{ steps.submit.outputs.id }}
run: |
echo "::group::Cancel job"
testflinger --server $SERVER cancel $JOB_ID
echo "::endgroup::"