-
Notifications
You must be signed in to change notification settings - Fork 1
194 lines (169 loc) · 8.07 KB
/
collect-instance-uptime.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
name: Collect Instance Uptime
on:
schedule:
# Run every 5 mins
- cron: "* * * * *"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ vars.MORPHOCLOUD_OS_CLOUD }}
cancel-in-progress: true
jobs:
collect-instance-uptime:
runs-on: self-hosted
steps:
- uses: actions/checkout@v4
- name: Define metadata
id: define-metadata
run: |
echo "branch=instance-uptime-data" >> $GITHUB_OUTPUT
echo "directory=data" >> $GITHUB_OUTPUT
- name: Create & push branch
run: |
exist_in_remote=$(git ls-remote --heads origin $BRANCH)
if [[ -z ${exist_in_remote} ]]; then
echo "Creating $BRANCH branch"
mkdir $DIRECTORY
cp -r .git $DIRECTORY/.git
cd $DIRECTORY
user_name='github-actions[bot]'
git config user.name "$user_name" && echo "user.name: ${user_name}"
user_email='41898282+github-actions[bot]@users.noreply.github.com'
git config user.email "$user_email" && echo "user.email: ${user_email}"
git checkout --orphan $BRANCH
git reset --hard
git commit --allow-empty -m "Initializing $BRANCH branch"
git push origin $BRANCH
fi
env:
BRANCH: ${{ steps.define-metadata.outputs.branch }}
DIRECTORY: ${{ steps.define-metadata.outputs.directory }}
- uses: actions/checkout@v4
with:
ref: instance-uptime-data
path: ${{ steps.define-metadata.outputs.directory }}
- name: Collect Instance Uptime
id: collect-instance-uptime
run: |
source ~/venv/bin/activate
instance_prefix=${PREFIX:+${PREFIX}_}
instance_basename="${instance_prefix}instance"
# Define the JSON file paths for storing/updating uptimes
JSON_FILE=$JSON_DIR/uptime.json
JSON_FILE_TMP=$(mktemp $RUNNER_TEMP/uptime.XXXXXX.json)
# Initialize the JSON file if it doesn't exist, with a basic structure
if [[ ! -f $JSON_FILE ]]; then
jq --null-input \
--arg allocation_id "$OS_CLOUD" \
'{"allocations": [{"id": $allocation_id, "instances": []}]}' > $JSON_FILE
fi
# List all instances matching the naming pattern and process each one
openstack server list --name "^${instance_basename}-\d+" -f json | \
jq -r '.[] | [.Name, .Status, ."OS-EXT-STS:task_state"] | @tsv' | \
while IFS=$'\t' read -r instance_name status task_state; do
echo "instance_name [$instance_name] status [$status] task_state [$task_state]"
# Skip the instance if it is not active
if [[ "$status" != "ACTIVE" ]]; then
continue
fi
if [[ "$task_state" != "" ]]; then
continue
fi
# Extract issue number
issue_number=${instance_name##*-}
echo "issue_number [$issue_number]"
# Retrieve the IP address of the instance
instance_ip=$(
openstack server show $instance_name -c addresses -f json | \
jq -r '.addresses.auto_allocated_network[1]'
)
echo "instance_ip [$instance_ip]"
# Skip the instance if the IP address could not be retrieved
if [[ "$instance_ip" == "null" ]]; then
echo "::warning ::Failed to retrieve $instance_name IP"
continue
fi
# Notes on SSH usage:
# * Redirecting SSH standard input to /dev/null ('< /dev/null') is required to work around
# an issue where SSH breaks out of the while loop in Bash.
# Reference: https://stackoverflow.com/questions/9393038/ssh-breaks-out-of-while-loop-in-bash
# Retrieve the instance uptime using SSH
uptime=$(ssh \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
-o LogLevel=ERROR \
exouser@$instance_ip \
'cat /proc/uptime | awk "{print \$1}"' < /dev/null)
if [[ $? -ne 0 ]]; then
echo "::warning ::Failed to retrieve uptime for $instance_name using IP $instance_ip"
continue
fi
# Retrieve the startup time of the instance in yyyy-mm-dd HH:MM:SS format
startup_time=$(ssh \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
-o LogLevel=ERROR \
exouser@$instance_ip \
'uptime -s' < /dev/null)
if [[ $? -ne 0 ]]; then
echo "::warning ::Failed to retrieve startup time for $instance_name using IP $instance_ip"
continue
fi
# Check if the instance is already recorded in the JSON file
has_instance=$(cat $JSON_FILE | jq \
--arg allocation_id "$OS_CLOUD" \
--arg instance_name "$instance_name" \
--arg startup_time "$startup_time" \
'any(.allocations[] | select(.id == $allocation_id) | .instances[]; .name == $instance_name)')
# If the instance is not found, add it to the JSON file
if [[ "$has_instance" == "false" ]]; then
cat $JSON_FILE | jq \
--arg allocation_id "$OS_CLOUD" \
--arg instance_name "$instance_name" \
'(.allocations[] | select(.id == $allocation_id) | .instances)
+= [{"name": $instance_name, "uptimes": {}}]' > $JSON_FILE_TMP \
&& mv $JSON_FILE_TMP $JSON_FILE
fi
# Check if there is an uptime entry for the startup time
has_startup_time=$(cat $JSON_FILE | jq \
--arg allocation_id "$OS_CLOUD" \
--arg instance_name "$instance_name" \
--arg startup_time "$startup_time" \
'(.allocations[] | select(.id == $allocation_id) | .instances[] | select(.name == $instance_name) | .uptimes | has($startup_time))')
if [[ "$has_startup_time" == "false" ]]; then
# If the startup time is not recorded, add the uptime entry
cat $JSON_FILE | jq \
--arg allocation_id "$OS_CLOUD" \
--arg instance_name "$instance_name" \
--arg startup_time "$startup_time" \
--arg uptime "$uptime" \
'(.allocations[] | select(.id == $allocation_id) | .instances[] | select(.name == $instance_name) | .uptimes)
+= {($startup_time): $uptime|tonumber}' > $JSON_FILE_TMP \
&& mv $JSON_FILE_TMP $JSON_FILE
else
# If the startup time is already recorded, update the uptime entry
cat $JSON_FILE | jq \
--arg allocation_id "$OS_CLOUD" \
--arg instance_name "$instance_name" \
--arg startup_time "$startup_time" \
--arg uptime "$uptime" \
'(.allocations[] | select(.id == $allocation_id) | .instances[] | select(.name == $instance_name) | .uptimes[$startup_time])
= ($uptime|tonumber)' > $JSON_FILE_TMP \
&& mv $JSON_FILE_TMP $JSON_FILE
fi
done
# Display the final JSON content for verification
echo "--------"
cat $JSON_FILE
echo "--------"
env:
OS_CLOUD: ${{ vars.MORPHOCLOUD_OS_CLOUD }}
PREFIX: ${{ vars.INSTANCE_NAME_PREFIX }}
JSON_DIR: ${{ steps.define-metadata.outputs.directory }}
- name: Publish
uses: s0/git-publish-subdir-action@61eb9e6420447e7cbf010f7cce37103665c46bfa # develop
env:
REPO: self
BRANCH: ${{ steps.define-metadata.outputs.branch }}
FOLDER: ${{ steps.define-metadata.outputs.directory }}
SQUASH_HISTORY: true
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}