Merge ~mitchdz/ubuntu/+source/ec2-hibinit-agent:mitch/xenial-imdsv2 into ubuntu/+source/ec2-hibinit-agent:ubuntu/xenial-devel

Proposed by Mitchell Dzurick
Status: Merged
Merge reported by: Mitchell Dzurick
Merged at revision: 577603dc5c8a0c3bce9c6992f28532985a514c2e
Proposed branch: ~mitchdz/ubuntu/+source/ec2-hibinit-agent:mitch/xenial-imdsv2
Merge into: ubuntu/+source/ec2-hibinit-agent:ubuntu/xenial-devel
Diff against target: 375 lines (+312/-2)
8 files modified
debian/changelog (+16/-0)
debian/ec2-hibinit-agent.install (+1/-0)
debian/hibinit-agent.system-sleep (+1/-2)
debian/hibinit-resume (+48/-0)
debian/patches/lp1941785-Add-support-for-IMDSv2.patch (+161/-0)
debian/patches/lp1968805-Swapon-with-maximum-priority-before-hibernation.patch (+63/-0)
debian/patches/lp2023924-remove-quotes-from-state-dir.patch (+19/-0)
debian/patches/series (+3/-0)
Reviewer Review Type Date Requested Status
git-ubuntu import Pending
Review via email: mp+456027@code.launchpad.net
To post a comment you must log in.
92c89f4... by Mitchell Dzurick

debian/hibinit-resume: Add extra steps around swapoff to avoid OOM errors.

4054ec8... by Mitchell Dzurick

d/p/lp1968805-Swapon-with-maximum-priority-before-hibernation.patch: Swapon with maximum priority right before hibernation.

13f7bf9... by Mitchell Dzurick

d/p/{lp1941785,lp2023924}*: add IMDSv2, fix quotes bug created from IMDSv2 patch

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/debian/changelog b/debian/changelog
2index b366dca..b4f95a5 100644
3--- a/debian/changelog
4+++ b/debian/changelog
5@@ -1,3 +1,19 @@
6+ec2-hibinit-agent (1.0.0-0ubuntu4~16.04.5) xenial; urgency=medium
7+
8+ * d/p/lp2023924-remove-quotes-from-state-dir.patch: fixes an issue where a
9+ weird directory would be created in root (LP: #2023924)
10+ * d/p/lp1941785-Add-support-for-IMDSv2.patch: allow hibernation of
11+ AWS EC2 instances with IMDSv2 (LP: #1941785)
12+ * Swapon with maximum priority right before hibernation. This resolves
13+ swapfile priority issues with additional or multiple swapfiles enabled.
14+ (LP: #1968805)
15+ - d/p/lp1968805-Swapon-with-maximum-priority-before-hibernation.patch
16+ * debian/hibinit-resume: Add extra steps around swapoff to avoid OOM errors.
17+ Also work around xen-netfront not resuming properly.
18+ Thanks to Francis Ginther for the initial patch (LP: #1863242, #1864041)
19+
20+ -- Mitchell Dzurick <mitchell.dzurick@canonical.com> Tue, 21 Nov 2023 15:31:14 -0700
21+
22 ec2-hibinit-agent (1.0.0-0ubuntu4~16.04.4) xenial; urgency=medium
23
24 * Always set resume device by PARTUUID instead of by device name.
25diff --git a/debian/ec2-hibinit-agent.install b/debian/ec2-hibinit-agent.install
26index b140d28..5b1b272 100755
27--- a/debian/ec2-hibinit-agent.install
28+++ b/debian/ec2-hibinit-agent.install
29@@ -5,5 +5,6 @@ debian/ec2-hibinit-agent-ignore-powerkey.conf usr/lib/systemd/logind.conf.d/
30 debian/hibinit-agent.system-sleep => lib/systemd/system-sleep/hibinit-agent
31 debian/hibinit-power etc/acpi/events
32 debian/hibinit-power.sh etc/acpi/actions
33+debian/hibinit-resume usr/lib/ec2-hibinit-agent
34 etc/hibinit-config.cfg
35 agent/* usr/bin/
36diff --git a/debian/hibinit-agent.system-sleep b/debian/hibinit-agent.system-sleep
37index 914161b..62db7bd 100755
38--- a/debian/hibinit-agent.system-sleep
39+++ b/debian/hibinit-agent.system-sleep
40@@ -4,8 +4,7 @@ set -e
41 if [ "$2" = "hibernate" ] || [ "$2" = "hybrid-sleep" ]; then
42 case "$1" in
43 post)
44- systemctl restart --no-block systemd-networkd
45- systemd-run --no-block --service-type=oneshot swapoff /swap-hibinit
46+ systemd-run --no-block --service-type=oneshot /usr/lib/ec2-hibinit-agent/hibinit-resume
47 ;;
48 esac
49 fi
50diff --git a/debian/hibinit-resume b/debian/hibinit-resume
51new file mode 100755
52index 0000000..e83fe2c
53--- /dev/null
54+++ b/debian/hibinit-resume
55@@ -0,0 +1,48 @@
56+#!/bin/bash
57+#
58+# Resume from hibernation on EC2 and apply workarounds for various issues
59+#
60+# Copyright (C) 2020 Canonical Ltd.
61+#
62+
63+set -e
64+
65+# Starting hibinit resume actions
66+echo "hibinit-resume: begin" >> /var/log/hibinit-resume.log
67+
68+# Give some time to make sure the system is fully up and running, see LP: #1864041
69+sleep 2
70+
71+# Make sure the network is properly resumed
72+echo "restarting network" >> /var/log/hibinit-resume.log
73+if grep -q xen_netfront /proc/modules; then
74+ # Xen netfront workaround LP: #1864041
75+ modprobe -r xen_netfront
76+ modprobe xen_netfront
77+fi
78+systemctl restart --no-block systemd-networkd
79+
80+# Temporarily set memory allocation policy to "always overcommit". With
81+# the default overcommit policy some applications might experience
82+# out-of-memory errors. Setting the policy to "always overcommit" seems
83+# to be a safe way to prevent these errors.
84+OVERCOMMIT_POLICY=$(cat /proc/sys/vm/overcommit_memory)
85+echo 1 > /proc/sys/vm/overcommit_memory
86+# Start swapoff and make sure swap file is gone
87+while :; do
88+ echo "starting swapoff" >> /var/log/hibinit-resume.log
89+ swapoff /swap-hibinit
90+ if grep -q swap-hibinit /proc/swaps; then
91+ echo "swap still active" >> /var/log/hibinit-resume.log
92+ sleep 10
93+ else
94+ break
95+ fi
96+done
97+echo "swap disabled" >> /var/log/hibinit-resume.log
98+cat /proc/swaps >> /var/log/hibinit-resume.log
99+# Restore previou overcommit policy
100+echo "$OVERCOMMIT_POLICY" > /proc/sys/vm/overcommit_memory
101+
102+# All done
103+echo "hibinit-resume: completed " >> /var/log/hibinit-resume.log
104diff --git a/debian/patches/lp1941785-Add-support-for-IMDSv2.patch b/debian/patches/lp1941785-Add-support-for-IMDSv2.patch
105new file mode 100644
106index 0000000..6855eb2
107--- /dev/null
108+++ b/debian/patches/lp1941785-Add-support-for-IMDSv2.patch
109@@ -0,0 +1,161 @@
110+Description: Add support for IMDSv2
111+Author: Frederick Lefebvre <fredlef@amazon.com>
112+Origin: backport, https://github.com/aws/amazon-ec2-hibinit-agent/commit/9d9bca5c61fa9256289e68c88bd3747af2f62e28
113+Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/ec2-hibinit-agent/+bug/1941785
114+Last-Update: 2023-05-16
115+---
116+This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
117+--- a/agent/hibinit-agent
118++++ b/agent/hibinit-agent
119+@@ -18,6 +18,7 @@
120+ import sys
121+ import syslog
122+ import math
123++import requests
124+ from subprocess import check_call, check_output, STDOUT
125+ from threading import Thread
126+ from math import ceil
127+@@ -25,11 +26,6 @@
128+
129+
130+ try:
131+- from urllib.request import urlopen, Request
132+-except ImportError:
133+- from urllib2 import urlopen, Request, HTTPError
134+-
135+-try:
136+ from ConfigParser import ConfigParser, NoSectionError, NoOptionError
137+ except:
138+ from configparser import ConfigParser, NoSectionError, NoOptionError
139+@@ -41,7 +37,12 @@
140+ log_to_syslog = True
141+ log_to_stderr = True
142+ SWAP_FILE = '/swap-hibinit'
143+-URL = "http://169.254.169.254/latest/meta-data/hibernation/configured"
144++
145++DEFAULT_STATE_DIR = '/var/lib/hibinit-agent'
146++HIB_ENABLED_FILE = "hibernation-enabled"
147++IMDS_BASEURL = 'http://169.254.169.254'
148++IMDS_API_TOKEN_PATH = 'latest/api/token'
149++IMDS_SPOT_ACTION_PATH = 'latest/meta-data/hibernation/configured'
150+
151+ def log(message):
152+ if log_to_syslog:
153+@@ -314,6 +315,9 @@
154+ get_int('swap', 'percentage-of-ram'), args.swap_ram_percentage, 100)
155+ self.swap_mb = self.merge(
156+ get_int('swap', 'target-size-mb'), args.swap_target_size_mb, 4000)
157++ self.state_dir = get('core', 'state-dir')
158++ if self.state_dir is None:
159++ self.state_dir = DEFAULT_STATE_DIR
160+
161+
162+ def merge(self, cf_value, arg_value, def_val):
163+@@ -337,31 +341,55 @@
164+ def __str__(self):
165+ return str(self.__dict__)
166+
167+-def hibernationEnabled():
168+- """Returns a boolean indicating whether hibernation is enabled or not."""
169+- response = None
170+- try:
171+- response = urlopen(URL)
172+- data = response.read()
173+- if data.lower() in ('false', b'false'):
174+- return False
175+- except:
176+- return False
177+- finally:
178+- if response:
179+- response.close()
180+- return True
181++def get_imds_token(seconds=21600):
182++ """ Get a token to access instance metadata. """
183++ log("Requesting new IMDSv2 token.")
184++ request_header = {'X-aws-ec2-metadata-token-ttl-seconds': str(seconds)}
185++ token_url = '{}/{}'.format(IMDS_BASEURL, IMDS_API_TOKEN_PATH)
186++ response = requests.put(token_url, headers=request_header)
187++ response.close()
188++ if response.status_code != 200:
189++ return None
190++
191++ return response.text
192++
193++def create_state_dir(state_dir):
194++ """ Create agent run dir if it doesn't exists."""
195++ if not os.path.isdir(state_dir):
196++ os.makedirs(state_dir)
197++
198++def hibernation_enabled(state_dir):
199++ """Returns a boolean indicating whether hibernation is enabled or not.
200++ Hibernation can't be enabled/disabled the instance launch. If we find
201++ hibernation to be enabled, we create a semephore file so that we don't
202++ have to probe IMDS again. That is useful when a instance is rebooted
203++ after/if the IMDS http endpoint has been disabled.
204++ """
205++ hib_sem_file = os.path.join(state_dir, HIB_ENABLED_FILE)
206++ if os.path.isfile(hib_sem_file):
207++ log("Found {!r}, configuring hibernation".format(hib_sem_file))
208++ return True
209++
210++ imds_token = get_imds_token()
211++ if imds_token is None:
212++ # IMDS http endpoint is disabled
213++ return False
214++
215++ request_header = {'X-aws-ec2-metadata-token': imds_token}
216++ response = requests.get("{}/{}".format(IMDS_BASEURL, IMDS_SPOT_ACTION_PATH),
217++ headers=request_header)
218++ response.close()
219++ if response.status_code != 200 or response.text.lower() == "false":
220++ return False
221++
222++ log("Hibernation Configured Flag found")
223++ os.mknod(hib_sem_file)
224++
225++ return True
226++
227+
228+ def main():
229+
230+- if not hibernationEnabled():
231+- log("Instance Launch has not enabled Hibernation Configured Flag. hibinit-agent exiting!!")
232+- exit(0)
233+- # Validate if disk space>total RAM
234+- ram_bytes = os.sysconf('SC_PAGE_SIZE') * os.sysconf('SC_PHYS_PAGES')
235+- if get_rootfs_size()<=(math.ceil(float(ram_bytes)/(1024*1024*1024))):
236+- log("Insufficient disk space. Cannot create setup for hibernation. Please allocate a larger root device")
237+- exit(1)
238+ # Parse arguments
239+ parser = argparse.ArgumentParser(description="An EC2 background process that creates a setup for instance hibernation "
240+ "at instance launch and also registers ACPI sleep event/actions")
241+@@ -388,6 +416,17 @@
242+ log_to_syslog = config.log_to_syslog
243+
244+ log("Effective config: %s" % config)
245++ create_state_dir(config.state_dir)
246++
247++ # Let's first check if we even need to run
248++ if not hibernation_enabled(config.state_dir):
249++ log("Instance Launch has not enabled Hibernation Configured Flag. hibinit-agent exiting!!")
250++ exit(0)
251++ # Validate if disk space>total RAM
252++ ram_bytes = os.sysconf('SC_PAGE_SIZE') * os.sysconf('SC_PHYS_PAGES')
253++ if get_rootfs_size()<=(math.ceil(float(ram_bytes)/(1024*1024*1024))):
254++ log("Insufficient disk space. Cannot create setup for hibernation. Please allocate a larger root device")
255++ exit(1)
256+
257+ target_swap_size = config.swap_mb * 1024 * 1024
258+ swap_percentage_size = ram_bytes * config.swap_percentage // 100
259+--- a/etc/hibinit-config.cfg
260++++ b/etc/hibinit-config.cfg
261+@@ -11,6 +11,9 @@
262+ # filesystems.
263+ touch-swap = False
264+
265++# Location where to create any state files
266++state-dir = "/var/lib/hibinit-agent"
267++
268+ [swap]
269+ # If there's no swap then we create it to be equal to the specified
270+ # percentage of RAM or to the target size, whichever is greater
271diff --git a/debian/patches/lp1968805-Swapon-with-maximum-priority-before-hibernation.patch b/debian/patches/lp1968805-Swapon-with-maximum-priority-before-hibernation.patch
272new file mode 100644
273index 0000000..5ed11c1
274--- /dev/null
275+++ b/debian/patches/lp1968805-Swapon-with-maximum-priority-before-hibernation.patch
276@@ -0,0 +1,63 @@
277+Author: Matthew Ruffell <matthew.ruffell@canonical.com>
278+Date: Wed 13 Apr 2022 15:39:15 +1200
279+Description:
280+
281+ Swapon with maximum priority before hibernation
282+
283+ Since Focal, on systems with additional or multiple swapfiles
284+ configured, swapon on /swap-hibinit will be added with the next
285+ lowest priority for the system.
286+
287+ For example, if we have /swapfile configured with a default priority
288+ of -2, swapon /swap-hibinit will be added with priority -3.
289+
290+ $ sudo swapon /swapfile
291+ $ swapon --show
292+ NAME TYPE SIZE USED PRIO
293+ /swapfile file 4G 0B -2
294+ $ sudo swapon /swap-hibinit
295+ $ swapon --show
296+ NAME TYPE SIZE USED PRIO
297+ /swapfile file 4G 0B -2
298+ /swap-hibinit file 3.9G 0B -3
299+
300+ This causes hibernation to fail, since hibernation targets the
301+ highest priority swapfile, which is no longer /swap-hibinit, and the
302+ kernel command line is specifically configured to resume from the
303+ UUID and offset for /swap-hibinit.
304+
305+ The result is that EC2 console says "Stopping" for 20 minutes before
306+ the instance is force stopped.
307+
308+ Fix this by setting /swap-hibinit to maximum possible priority,
309+ 32767, as we swapon right before hibernation takes place.
310+
311+Bug-Ubuntu: https://bugs.launchpad.net/bugs/1968805
312+Forwarded: yes, https://github.com/aws/amazon-ec2-hibinit-agent/commit/a2303d269610a6e7415c5045766da605eaa7e30f
313+Last-Update: 2022-04-13
314+
315+Index: ec2-hibinit-agent-1.0.0/acpid.sleep.sh
316+===================================================================
317+--- ec2-hibinit-agent-1.0.0.orig/acpid.sleep.sh 2022-04-13 15:55:57.642062380 +1200
318++++ ec2-hibinit-agent-1.0.0/acpid.sleep.sh 2022-04-13 15:55:57.642062380 +1200
319+@@ -2,6 +2,11 @@
320+
321+ #PATH=/sbin:/bin:/usr/bin
322+
323++# Hibernation selects the swapfile with highest priority. Since there may be
324++# other swapfiles configured, ensure /swap-hibinit is selected as hibernation
325++# target by setting to maximum priority. See LP#1968805.
326++swap_priority=32767
327++
328+ do_hibernate() {
329+ if [ -d /run/systemd/system ]; then
330+ systemctl hibernate
331+@@ -14,7 +19,7 @@
332+
333+ case "$2" in
334+ SBTN)
335+- swapon /swap-hibinit && do_hibernate
336++ swapon --priority=$swap_priority /swap-hibinit && do_hibernate
337+ ;;
338+ *)
339+ logger "ACPI action undefined: $2" ;;
340diff --git a/debian/patches/lp2023924-remove-quotes-from-state-dir.patch b/debian/patches/lp2023924-remove-quotes-from-state-dir.patch
341new file mode 100644
342index 0000000..d178d21
343--- /dev/null
344+++ b/debian/patches/lp2023924-remove-quotes-from-state-dir.patch
345@@ -0,0 +1,19 @@
346+Description: Remove quotes in config file for state_dir value
347+It creates strange directory /"
348+Author: Anchal Agarwal <anchalag@amazon.com>
349+Origin: backport, https://github.com/aws/amazon-ec2-hibinit-agent/commit/d87d6365009f1663247fd8595b487c59d9b121f1
350+Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/ec2-hibinit-agent/+bug/2023924
351+Last-Update: 2023-06-20
352+---
353+This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
354+--- a/etc/hibinit-config.cfg
355++++ b/etc/hibinit-config.cfg
356+@@ -12,7 +12,7 @@
357+ touch-swap = False
358+
359+ # Location where to create any state files
360+-state-dir = "/var/lib/hibinit-agent"
361++state-dir = /var/lib/hibinit-agent
362+
363+ [swap]
364+ # If there's no swap then we create it to be equal to the specified
365diff --git a/debian/patches/series b/debian/patches/series
366index 136d930..1555533 100644
367--- a/debian/patches/series
368+++ b/debian/patches/series
369@@ -7,3 +7,6 @@ detect-hibernate-cmd-by-default.patch
370 0008-Detect-disabled-hibernation-with-Python-3-s-urllib-t.patch
371 0008-Always-set-resume-device-by-PARTUUID-instead-of-by-d.patch
372 0010-Update-grub-configuration-when-it-needs-an-update.patch
373+lp1968805-Swapon-with-maximum-priority-before-hibernation.patch
374+lp1941785-Add-support-for-IMDSv2.patch
375+lp2023924-remove-quotes-from-state-dir.patch

Subscribers

People subscribed via source and target branches