pax_global_header00006660000000000000000000000064146262033320014513gustar00rootroot0000000000000052 comment=527a5f69bcd0c6c8ca7612f541b4dabc3f32b118 amazon-ec2-hibinit-agent-1.0.9/000077500000000000000000000000001462620333200161765ustar00rootroot00000000000000amazon-ec2-hibinit-agent-1.0.9/.github/000077500000000000000000000000001462620333200175365ustar00rootroot00000000000000amazon-ec2-hibinit-agent-1.0.9/.github/PULL_REQUEST_TEMPLATE.md000066400000000000000000000002441462620333200233370ustar00rootroot00000000000000Issue #, if available: Description of changes: By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. amazon-ec2-hibinit-agent-1.0.9/.gitignore000066400000000000000000000000131462620333200201600ustar00rootroot00000000000000 .DS_Store amazon-ec2-hibinit-agent-1.0.9/LICENSE.txt000066400000000000000000000267501462620333200200330ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ## Runtime Library Exception to the Apache 2.0 License: ## As an exception, if you use this Software to compile your source code and portions of this Software are embedded into the binary product as a result, you may redistribute such product without providing attribution as would otherwise be required by Sections 4(a), 4(b) and 4(d) of the License. amazon-ec2-hibinit-agent-1.0.9/MANIFEST.in000066400000000000000000000001541462620333200177340ustar00rootroot00000000000000include README.md LICENSE.txt include acpid.sleep.conf include acpid.sleep.sh include hibinit-agent.service amazon-ec2-hibinit-agent-1.0.9/Makefile000066400000000000000000000002051462620333200176330ustar00rootroot00000000000000sources: python2.7 setup.py sdist --formats=gztar mv dist/*.gz . rm -rf dist clean: rm *.gz rm -rf ec2_hibinit_agent.egg-info amazon-ec2-hibinit-agent-1.0.9/README.md000066400000000000000000000054321462620333200174610ustar00rootroot00000000000000The Amazon Linux hibernation agent. The purpose of this agent is to create a setup for an instance to support hibernation feature. The setup is created only on supported instance types. This agent does several things upon startup: 1. It checks for sufficient swap space to allow hibernation and fails if not enough space 2. If there's no swap file or the existing swap file isn't of a sufficient size, a swap file is created 1. If `touch-swap` is enabled, all the swap file's blocks will be touched so that the root EBS volume is pre-warmed. 3. It updates the offset of the swap file in the kernel using `snapshot_set_swap_area` ioctl. 4. It updates the resume offset and resume device in grub file. ## Building in Red hat 1- Install Development Tools in Red Hat to build the RPM package ``` sudo dnf group install "Development Tools" mkdir -p ~/rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS} ``` 2- Install required build packages for ec2-hibernate-linux-agent. ``` sudo yum install python3-devel sudo yum install selinux-policy-devel ``` 3- Download the package from github repository. You can replace `1.0.3` with any release version number. ``` echo '%_topdir %(echo $HOME)/rpmbuild' > ~/.rpmmacros wget https://github.com/aws/amazon-ec2-hibinit-agent/archive/v1.0.3/ec2-hibinit-agent-1.0.3.tar.gz tar -xf ec2-hibinit-agent-1.0.3.tar.gz ``` 4- Copy spec file to SPEC directory. ``` cd ~/rpmbuild//SPECS cp ~/rpmbuild/SOURCES/amazon-ec2-hibinit-agent-1.0.3/packaging/rhel/ec2-hibinit-agent.spec ~/rpmbuild/SPECS/ ``` 5- Build the Spec file ``` nohup rpmbuild -bb --target=noarch ec2-hibinit-agent.spec ``` You will find the RPM package generated at `~/rpmbuild/RPMS/noarch/` directory ## Building in SUSE Linux 1- Install Development Tools in Suse Linux to build the RPM package ``` sudo zypper install rpm-build mkdir -p ~/rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS} ``` 2- Install required build packages for ec2-hibernate-linux-agent. ``` sudo zypper install python3-devel sudo zypper install tuned sudo zypper install python-rpm-generators ``` 3- Download the package from github repository. You can replace `1.0.3` with any release version number. ``` echo '%_topdir %(echo $HOME)/rpmbuild' > ~/.rpmmacros cd ~/rpmbuild/SOURCES wget https://github.com/aws/amazon-ec2-hibinit-agent/archive/v1.0.3/ec2-hibinit-agent-1.0.3.tar.gz tar -xf ec2-hibinit-agent-1.0.3.tar.gz ``` 4- Copy spec file to SPEC directory. You can replace `1.0.3` with any release version number. ``` cd ~/rpmbuild//SPECS cp ~/rpmbuild/SOURCES/amazon-ec2-hibinit-agent-1.0.3/packaging/sles/ec2-hibinit-agent.spec ~/rpmbuild/SPECS/ ``` 5- Build the Spec file ``` nohup rpmbuild -bb --target=noarch ec2-hibernate-linux-agent.spec ``` You will find the RPM package generated at `~/rpmbuild/RPMS/noarch/` directory amazon-ec2-hibinit-agent-1.0.9/acpid.sleep.conf000066400000000000000000000002531462620333200212340ustar00rootroot00000000000000# ACPID config to power down machine if powerbutton is pressed, but only if # no gnome-power-manager is running event=button/sleep.* action=/etc/acpi/actions/sleep.sh %e amazon-ec2-hibinit-agent-1.0.9/acpid.sleep.sh000077500000000000000000000017701462620333200207310ustar00rootroot00000000000000#!/bin/sh PATH=/sbin:/bin:/usr/bin failed='false' # Hibernation selects the swapfile with highest priority. Since there may be # other swapfiles configured, ensure /swap is selected as hibernation # target by setting to maximum priority. swap_priority=32767 hibernate() { swapon --priority=$swap_priority /swap && /usr/sbin/pm-hibernate if [ $? -ne 0 ] then logger "Hibernation failed, Sleeping 2 mins before retry" failed='true' else failed='false' fi swapoff /swap } case "$2" in SBTN) # The iteration had been placed here to add retry logic to hibernation # in case of failures and to avoid force stop of instances after 20min for i in 1 2 3 do hibernate if [ $failed == 'true' ]; then swapoff /swap sleep 2m else break fi done ;; *) logger "ACPI action undefined: $2" ;; esac amazon-ec2-hibinit-agent-1.0.9/agent/000077500000000000000000000000001462620333200172745ustar00rootroot00000000000000amazon-ec2-hibinit-agent-1.0.9/agent/hibinit-agent000077500000000000000000000501671462620333200217550ustar00rootroot00000000000000#!/usr/libexec/platform-python # AWS EC2 HibInit Agent. This agent does several things upon startup: # 1. It checks for sufficient swap space to allow hibernation and fails if not enough space # 2. If there's no swap file or the existing swap file isn't of a sufficient size, a swap file is created # 1. If `touch-swap` is enabled, all the swap file's blocks will be touched # so that the root EBS volume is pre-warmed. # 3. It updates the offset of the swap file in the kernel using `snapshot_set_swap_area` ioctl. # 4. It updates the resume offset and resume device in grub file. # # This file is compatible both with Python 2 and Python 3 import argparse import array import ctypes as ctypes import fcntl import mmap import os import struct import sys import syslog import math import requests import signal from subprocess import check_call, check_output try: from ConfigParser import ConfigParser, NoSectionError, NoOptionError except: from configparser import ConfigParser, NoSectionError, NoOptionError # Space reserved for swap headers SWAP_RESERVED_SIZE = 16384 LOG_TO_SYSLOG = True SWAP_FILE = '/swap' DEFAULT_STATE_DIR = '/var/lib/hibinit-agent' HIB_ENABLED_FILE = "hibernation-enabled" IMDS_BASEURL = 'http://169.254.169.254' IMDS_API_TOKEN_PATH = 'latest/api/token' IMDS_SPOT_ACTION_PATH = 'latest/meta-data/hibernation/configured' # Default Values KB = 1024 MAX_SWAP_SIZE_OFFSET_ALLOWED = 100 * KB DEFAULT_SWAP_SIZE_MB = 4000 DEFAULT_SWAP_PERCENTAGE = 100 # Sigterm_handler Behaviour Modifiers SHUTDOWN_REQUESTED = False def print_to_sys_log(message): if LOG_TO_SYSLOG: syslog.syslog(message) def critical_process_sigterm_handler(signum, frame): global SHUTDOWN_REQUESTED SHUTDOWN_REQUESTED = True def default_sigterm_handler(signum, frame): check_swapon_cmd = "swapon -s | cut -f1,1 | grep -w {name}" check_swapon_cmd = check_swapon_cmd.format(name=SWAP_FILE) check_swapon = check_output(check_swapon_cmd, shell=True) if check_swapon.strip() == SWAP_FILE: swapoff_cmd = "swapoff {filename}" swapoff_cmd = swapoff_cmd.format(filename=SWAP_FILE) check_call(swapoff_cmd, shell=True) if os.path.isfile(SWAP_FILE) and os.access(SWAP_FILE, os.R_OK): os.remove(SWAP_FILE) exit(0) def critical_process(function_with_critical_process): def wrapper(*args, **kwargs): signal.signal(signal.SIGTERM, critical_process_sigterm_handler) function_with_critical_process(*args, **kwargs) if SHUTDOWN_REQUESTED: exit(0) signal.signal(signal.SIGTERM, default_sigterm_handler) return wrapper def fallocate(fl, size): try: _libc = ctypes.CDLL('libc.so.6') _fallocate = _libc.fallocate _fallocate.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_ulong, ctypes.c_ulong] # (FD, mode, offset, len) res = _fallocate(fl.fileno(), 0, 0, size) if res != 0: raise Exception("Failed to perform fallocate(). Result: %d" % res) except Exception as e: print_to_sys_log("Failed to call fallocate(), will use resize. Err: %s" % str(e)) fl.seek(size - 1) fl.write(chr(0)) def get_file_block_number(filename): with open(filename, 'r') as handle: buf = array.array('L', [0]) # from linux/fs.h fibmap = 0x01 result = fcntl.ioctl(handle.fileno(), fibmap, buf) if result < 0: raise Exception("Failed to get the file offset. Error=%d" % result) return buf[0] def get_rootfs_size(): stat = os.statvfs('/') return math.ceil(float(stat.f_bsize * stat.f_blocks) / (KB * KB * KB)) # This is only for grub2 def find_grub_mount(): path_list = ['/etc/grub2-efi.cfg', '/boot/grub2/grub.cfg', '/boot/grub2-efi/grub.cfg', '/etc/grub2.cfg'] for ln in path_list: if os.path.isfile(ln) and os.access(ln, os.R_OK): find_mount_cmd = 'stat -L -c %m ' + ln mount = check_output(find_mount_cmd, shell=True, universal_newlines=True) return mount.strip() return None def patch_grub_config(swap_device, offset): mount_point = find_grub_mount() if mount_point is None: print_to_sys_log("Grub configuration is not updated. Grub cannot found under /boot or /etc. " + "Please run manual grub update with resume parameters") return print_to_sys_log("Updating GRUB to use the device %s with offset %d for resume" % (swap_device, offset)) grub_mkconfig = "grub2-mkconfig -o /boot/grub2/grub.cfg" check_call(grub_mkconfig, shell=True) grub_update_kernel = "grubby --update-kernel=ALL --args='no_console_suspend=1 " + \ "resume_offset={offset} resume={swap_device}'" grub_update_kernel = grub_update_kernel.format(offset=offset, swap_device=swap_device) check_call(grub_update_kernel, shell=True) fsfreeze = "sync && mountpoint -q {mount} && trap '' HUP INT QUIT TERM && " + \ "fsfreeze -f {mount} && fsfreeze -u {mount}" fsfreeze = fsfreeze.format(mount=mount_point) check_call(fsfreeze, shell=True) # Some grubby versions need a restart after changing in kernel parameters # echo offset and swap device helps the customer to use the agent immediately # after rpm installation. if os.path.exists("sys/power/resume"): echo_resume_device = "echo {swap_device} > /sys/power/resume" echo_resume_device = echo_resume_device.format(swap_device=swap_device) print_to_sys_log("sys/power/resume exist and will be updated") check_call(echo_resume_device, shell=True) if os.path.exists("/sys/power/resume_offset"): echo_resume_offset = "echo {offset} > /sys/power/resume_offset" echo_resume_offset = echo_resume_offset.format(offset=offset) print_to_sys_log("sys/power/resume_offset exist and will be updated") check_call(echo_resume_offset, shell=True) print_to_sys_log("GRUB configuration is updated") @critical_process def update_kernel_swap_offset(config): swapon = config.swapon.format(swapfile=SWAP_FILE) print_to_sys_log("Running: %s" % swapon) check_call(swapon, shell=True) print_to_sys_log("Updating the kernel offset for the swapfile: %s" % SWAP_FILE) statbuf = os.stat(SWAP_FILE) dev = statbuf.st_dev if config.btrfs_enabled: get_offset = "btrfs inspect-internal map-swapfile -r {swapfile}".format(swapfile=SWAP_FILE) offset = int(check_output(get_offset, shell=True).decode(sys.getfilesystemencoding())) else: offset = get_file_block_number(SWAP_FILE) if config.grub_update: dev_str = find_device_for_file(SWAP_FILE) patch_grub_config(dev_str, offset) else: print_to_sys_log("Skipping GRUB configuration update") print_to_sys_log("Setting swap device to %d with offset %d" % (dev, offset)) if not config.btrfs_enabled and os.path.exists("/dev/snapshot"): # Set the kernel swap offset, see https://www.kernel.org/doc/Documentation/power/userland-swsusp.txt # From linux/suspend_ioctls.h snapshot_set_swap_area = 0x400C330D buf = struct.pack('LI', offset, dev) with open('/dev/snapshot', 'r') as snap: fcntl.ioctl(snap, snapshot_set_swap_area, buf) print_to_sys_log("Done updating the swap offset. Turning swapoff") swapoff = config.swapoff.format(swapfile=SWAP_FILE) print_to_sys_log("Running: %s" % swapoff) check_call(swapoff, shell=True) check_call("trap '' HUP INT QUIT TERM && dracut -a resume -f", shell=True) def find_device_for_file(filename): # Find the mount point for the swap file ('df -P /swap') df_out = check_output(['df', '-P', filename]).decode(sys.getfilesystemencoding()) dev_str = df_out.split("\n")[1].split()[0] return dev_str class SwapInitializer(object): def __init__(self, config): self.swap_size = config.swap_mb * KB * KB self.config = config self.block_size = KB * KB # 1 MiB def init_swap(self): """ Initialize the swap using direct IO to avoid polluting the page cache """ if self.config.btrfs_enabled: self.setup_btrfs() self.do_allocate() if self.config.touch_swap: self.pretouch_swap() else: print_to_sys_log("Swap pre-heating is skipped, the swap blocks won't be touched during " "to ensure they are ready") self.init_mkswap() def setup_btrfs(self): no_cow = "truncate -s 0 {swapfile} && chattr +C {swapfile}".format(swapfile=SWAP_FILE) print_to_sys_log("Setting /swap to No Copy On Write") check_call(no_cow, shell=True) def do_allocate(self): print_to_sys_log("Allocating %d bytes in %s" % (self.swap_size, SWAP_FILE)) with open(SWAP_FILE, 'w+') as fl: fallocate(fl, self.swap_size) os.chmod(SWAP_FILE, 0o600) # Read + Write Permissions def pretouch_swap(self): written = 0 print_to_sys_log("Opening %s for direct IO" % SWAP_FILE) fd = os.open(SWAP_FILE, os.O_RDWR | os.O_DIRECT | os.O_SYNC | os.O_DSYNC) if fd < 0: raise Exception("Failed to open swap file. Err: %s" % os.strerror(os.errno)) filler_block = None try: # Create a filler block that is correctly aligned for direct IO filler_block = mmap.mmap(-1, self.block_size) # We're using 'b' to avoid optimizations that might happen for zero-filled pages filler_block.write(b'b' * self.block_size) print_to_sys_log("Touching all blocks in %s" % SWAP_FILE) while written < self.swap_size: res = os.write(fd, filler_block) if res <= 0: raise Exception("Failed to touch a block. Err: %s" % os.strerror(os.errno)) written += res finally: os.close(fd) if filler_block: filler_block.close() print_to_sys_log("Swap file %s is ready" % SWAP_FILE) def init_mkswap(self): # Do mkswap try: mkswap = self.config.mkswap.format(swapfile=SWAP_FILE) print_to_sys_log("Running: %s" % mkswap) check_call(mkswap, shell=True) except Exception as e: raise Exception(("Failed to setup swap area, reason: %s" % str(e))) def identify_file_system(swapfile, file_system): # Walk the parent directories of the swapfile to find on which # filesystem it's mounted swap_place = swapfile dev = None while not dev: swap_place, _ = os.path.split(swap_place) try: dev = find_device_for_file(swap_place) except: if swap_place == '/': raise Exception("Failed to find the filesystem type of %s" % swapfile) with open("/proc/mounts") as fl: lines = fl.read().split("\n") for ln in lines: if dev in ln and file_system in ln: return True return False class Config(object): def __init__(self, config_file, args): def get_from_config(section, name): try: return config_file.get(section, name) except NoSectionError: return None except NoOptionError: return None def get_int_from_config(section, name): v = get_from_config(section, name) return None if v is None else int(v) self.log_to_syslog = self.merge( self.to_bool(args.log_to_syslog), self.to_bool(get_from_config('core', 'log-to-syslog')), True) self.grub_update = self.merge( self.to_bool(args.grub_update), self.to_bool(get_from_config('core', 'grub-update')), True) self.touch_swap = self.merge( self.to_bool(args.touch_swap), self.to_bool(get_from_config('core', 'touch-swap')), identify_file_system(SWAP_FILE, "xfs")) self.btrfs_enabled = self.merge( self.to_bool(args.btrfs_enabled), self.to_bool(get_from_config('core', 'btrfs-enabled')), identify_file_system(SWAP_FILE, "btrfs")) self.state_dir = self.merge(None, get_from_config('core', 'state-dir'), DEFAULT_STATE_DIR) self.swap_percentage = self.merge(args.swap_ram_percentage, get_int_from_config('swap', 'percentage-of-ram'), DEFAULT_SWAP_PERCENTAGE) self.swap_mb = self.merge(args.swap_target_size_mb, get_int_from_config('swap', 'target-size-mb'), DEFAULT_SWAP_SIZE_MB) self.mkswap = self.merge(args.mkswap, get_from_config('swap', 'mkswap'), 'mkswap {swapfile}') self.swapon = self.merge(args.swapon, get_from_config('swap', 'swapon'), 'swapon {swapfile}') self.swapoff = self.merge(args.swapoff, get_from_config('swap', 'swapoff'), 'swapoff {swapfile}') def merge(self, arg_value, cf_value, def_val): if arg_value is not None: return arg_value if cf_value is not None: return cf_value return def_val def to_bool(self, bool_str): """Parse the string and return a boolean value, None, or raise an exception""" if bool_str is None: return None if bool_str.lower() in ['true', 't', '1']: return True elif bool_str.lower() in ['false', 'f', '0']: return False # if here we couldn't parse it raise ValueError("%s is not recognized as a boolean value" % bool_str) def __str__(self): return str(self.__dict__) def get_imds_token(seconds=21600): """ Get a token to access instance metadata. """ print_to_sys_log("Requesting new IMDSv2 token.") request_header = {'X-aws-ec2-metadata-token-ttl-seconds': '{}'.format(seconds)} token_url = '{}/{}'.format(IMDS_BASEURL, IMDS_API_TOKEN_PATH) response = requests.put(token_url, headers=request_header) response.close() if response.status_code != 200: return None return response.text def create_state_dir(state_dir): """ Create agent run dir if it doesn't exist.""" if not os.path.isdir(state_dir): os.makedirs(state_dir) def hibernation_enabled(state_dir): """Returns a boolean indicating whether hibernation is enabled or not. Hibernation can't be enabled/disabled after the instance launch. If we find hibernation to be enabled, we create a semaphore file so that we don't have to probe IMDS again. That is useful when an instance is rebooted after/if the IMDS http endpoint has been disabled. """ hib_sem_file = os.path.join(state_dir, HIB_ENABLED_FILE) if os.path.isfile(hib_sem_file): print_to_sys_log("Found {!r}, configuring hibernation".format(hib_sem_file)) return True imds_token = get_imds_token() if imds_token is None: # IMDS http endpoint is disabled return False request_header = {'X-aws-ec2-metadata-token': imds_token} response = requests.get("{}/{}".format(IMDS_BASEURL, IMDS_SPOT_ACTION_PATH), headers=request_header) response.close() if response.status_code != 200 or response.text.lower() == "false": return False print_to_sys_log("Hibernation Configured Flag found") os.mknod(hib_sem_file) return True # Returns a tuple denoting (valid_to_init_hibernation: bool, new_swap_file_required: bool) def validate_system_requirements(config): target_swap_size = config.swap_mb * KB * KB # Converting to bytes # Validate if disk space>total RAM ram_bytes = os.sysconf('SC_PAGE_SIZE') * os.sysconf('SC_PHYS_PAGES') if get_rootfs_size() <= (math.ceil(float(ram_bytes) / (KB * KB * KB))): print_to_sys_log( "Insufficient disk space. Cannot create setup for hibernation. Please allocate a larger root device") return False, False swap_percentage_size = ram_bytes * config.swap_percentage // 100 if swap_percentage_size > target_swap_size: target_swap_size = int(swap_percentage_size) print_to_sys_log("Will check if swap is at least: %d megabytes" % (target_swap_size // (KB * KB))) # Validate if swap file exists cur_swap = 0 if os.path.isfile(SWAP_FILE) and os.access(SWAP_FILE, os.R_OK): cur_swap = os.path.getsize(SWAP_FILE) if cur_swap > target_swap_size - SWAP_RESERVED_SIZE + MAX_SWAP_SIZE_OFFSET_ALLOWED: print_to_sys_log("Swap already exists! (have %d, need %d), deleting existing swap file %s since current swap is " "sufficiently large and wasting disk space" % (cur_swap, target_swap_size, SWAP_FILE)) os.remove(SWAP_FILE) elif cur_swap >= target_swap_size - SWAP_RESERVED_SIZE: print_to_sys_log("There's sufficient swap available (have %d, need %d)" % (cur_swap, target_swap_size)) return True, False # Validate if instance was launched from pre-created image and swap size>=total RAM, if not re-create the swap elif cur_swap > 0 and (cur_swap < target_swap_size - SWAP_RESERVED_SIZE): print_to_sys_log("Swap already exists! (have %d, need %d), deleting existing swap file %s" % (cur_swap, target_swap_size, SWAP_FILE)) os.remove(SWAP_FILE) # We need to create swap, but first validate that we have enough free space swap_dev = os.path.dirname(SWAP_FILE) st = os.statvfs(swap_dev) free_bytes = st.f_bavail * st.f_frsize # Rounding off to swap_size+10mb for swap headers free_space_needed = target_swap_size + 10 * KB * KB if free_space_needed >= free_bytes: print_to_sys_log("There's not enough space (%d present, %d needed) for the swap file on the device: %s" % ( free_bytes, free_space_needed, swap_dev)) return False, True print_to_sys_log("There's enough space (%d present, %d needed) for the swap file on the device: %s" % ( free_bytes, free_space_needed, swap_dev)) return True, True def main(): # Parse arguments parser = argparse.ArgumentParser( description="An EC2 background process that creates a setup for instance hibernation " "at instance launch and also registers ACPI sleep event/actions") parser.add_argument('-c', '--config', help='Configuration file to use', type=str) parser.add_argument("-syslog", "--log-to-syslog", help='Log to syslog', type=str) parser.add_argument("-grub", "--grub-update", help='Update GRUB config with resume offset', type=str) parser.add_argument("-touch", "--touch-swap", help='Do swap initialization', type=str) parser.add_argument("-btrfs", "--btrfs-enabled", help='Sets no copy on write on swap file', type=str) parser.add_argument("-p", "--swap-ram-percentage", help='The target swap size as a percentage of RAM', type=int) parser.add_argument("-s", "--swap-target-size-mb", help='The target swap size in megabytes', type=int) parser.add_argument('--mkswap', help='The command line utility to set up swap', type=str) parser.add_argument('--swapon', help='The command line utility to turn on swap', type=str) parser.add_argument('--swapoff', help='The command line utility to turn off swap', type=str) args = parser.parse_args() config_file = ConfigParser() if args.config: config_file.read(args.config) config = Config(config_file, args) global LOG_TO_SYSLOG LOG_TO_SYSLOG = config.log_to_syslog print_to_sys_log("Effective config: %s" % config) create_state_dir(config.state_dir) # Let's first check if we even need to run if not hibernation_enabled(config.state_dir): print_to_sys_log("Instance Launch has not enabled Hibernation Configured Flag. hibinit-agent exiting!!") exit(0) # Sets default termination handling signal.signal(signal.SIGTERM, default_sigterm_handler) valid_to_init_hibernation, new_swap_file_required = validate_system_requirements(config) if not valid_to_init_hibernation: exit(1) if new_swap_file_required: sw = SwapInitializer(config) try: sw.init_swap() except Exception as e: raise Exception("Failed to initialise swap file, reason: %s" % str(e)) update_kernel_swap_offset(config) if __name__ == '__main__': main() amazon-ec2-hibinit-agent-1.0.9/ec2-hibinit-agent.spec000066400000000000000000000075761462620333200222620ustar00rootroot00000000000000Name: ec2-hibinit-agent Version: 1.0.9 Release: 1%{?dist} Summary: Hibernation setup utility for AWS EC2 Group: System Environment/Daemons License: Apache 2.0 Source0: ec2-hibinit-agent-%{version}.tar.gz BuildArch: noarch BuildRequires: python2-devel BuildRequires: systemd %{?systemd_requires} Requires: acpid Requires: grubby Requires: pm-utils %description An EC2 agent that creates a setup for instance hibernation %prep %setup -q -n ec2-hibinit-agent-%{version} %build %{__python2} setup.py build %install %{__python2} setup.py install --prefix=usr -O1 --skip-build --root $RPM_BUILD_ROOT mkdir -p "%{buildroot}%{_unitdir}" mkdir -p %{buildroot}%{_sysconfdir}/acpi/events mkdir -p %{buildroot}%{_sysconfdir}/acpi/actions mkdir -p %{buildroot}%{_localstatedir}/lib/hibinit-agent install -p -m 644 "%{_builddir}/%{name}-%{version}/hibinit-agent.service" %{buildroot}%{_unitdir} install -p -m 644 "%{_builddir}/%{name}-%{version}/acpid.sleep.conf" %{buildroot}%{_sysconfdir}/acpi/events/sleepconf install -p -m 755 "%{_builddir}/%{name}-%{version}/acpid.sleep.sh" %{buildroot}%{_sysconfdir}/acpi/actions/sleep.sh %files %defattr(-,root,root) %doc README.md %{_sysconfdir}/hibinit-config.cfg %{_unitdir}/hibinit-agent.service %{_bindir}/hibinit-agent %dir %{_sysconfdir}/acpi %dir %{_sysconfdir}/acpi/events %dir %{_sysconfdir}/acpi/actions %config(noreplace) %attr(0644,root,root) %{_sysconfdir}/acpi/events/sleepconf %config(noreplace) %attr(0755,root,root) %{_sysconfdir}/acpi/actions/sleep.sh %{python2_sitelib}/* %dir %{_localstatedir}/lib/hibinit-agent %ghost %attr(0600,root,root) %{_localstatedir}/lib/hibinit-agent/hibernation-enabled %clean rm -rf $RPM_BUILD_ROOT %post %systemd_post hibinit-agent.service %preun %systemd_preun hibinit-agent.service %postun %systemd_postun_with_restart hibinit-agent.service %changelog * Thu May 16 2024 Seth Carolan - 1.0.9 - Confirm /dev/snapshot exists before updating resume parameters again. Parameters are already set via Grub config update. * Wed Jan 31 2024 Jeff Kim - 1.0.8-1 - Refactoring agent for legibility & changing service type to simple * Thu Dec 27 2023 Jeff Kim - 1.0.8 - Added better termination behaviour with a stop timeout of 2 minutes * Wed Oct 18 2023 Jeff Kim - 1.0.7 - Changed message when removing swap file - Adding btrfs-enabled to set No_COW and get offset using btrfs * Thu Sep 28 2023 Deborshi Saha - 1.0.6 - Add initial Amazon Linux 2022 support - Add pm-utils for required package - Recreate the swap file if the current size is sufficiently larger - Update /sys/power/resume_offset and /sys/power/resume only if present * Mon May 24 2021 Mohamed Aboubakr - 1.0.5 - Adding spec file for suse Linux - swapon with max priority when hibernating * Mon May 24 2021 Mohamed Aboubakr - 1.0.4 - grub2 mkconfig before grub configuration update - Update /sys/power after grub configuration update - Adding dracut to recreate initramfs after config update * Thu Jan 14 2021 Mohamed Aboubakr - 1.0.3 - Add python3 support - Support Redhat 8 by adding spec file for redhat and more configuration for acpid - Remove config no replace for files that do not exist in etc directory * Fri Jan 24 2020 Frederick Lefebvre - 1.0.1-2 - Restart the hibinit-agent service on upgrade * Thu Jan 23 2020 Frederick Lefebvre - 1.0.1-1 - Added IMDSv2 support - Renamed spec file to match the actual package name * Fri Jun 14 2019 Anchal Agarwal - 1.0.0-4 - Added hibernation re-try logic in case of hibernation failure * Wed Nov 07 2018 Matt Dees - 1.0.0-2 - Clean up hibernation configured check * Wed Oct 31 2018 Anchal Agarwal - 1.0.0-1 - Initial build amazon-ec2-hibinit-agent-1.0.9/etc/000077500000000000000000000000001462620333200167515ustar00rootroot00000000000000amazon-ec2-hibinit-agent-1.0.9/etc/hibinit-config.cfg000066400000000000000000000020261462620333200223230ustar00rootroot00000000000000[core] log-to-syslog = True # Automatically update GRUB config to include resume_offset for the swap file grub-update = True # Touch swap file to make sure EBS volume is pre-heated or on XFS filesystems that don't support # files with holes. # Leave out commented to automatically detect if swap touching is needed for XFS-based # filesystems. touch-swap = False # Adds No Copy-on-Write attribute and sets no compression to {swapfile}, required for btrfs systems to allow swap to work correctly # Leave out commented to automatically detect if this attribute needed to be set for btrfs btrfs-enabled = False # Location where to create any state files state-dir = /var/lib/hibinit-agent [swap] # If there's no swap then we create it to be equal to the specified # percentage of RAM or to the target size, whichever is greater percentage-of-ram = 100 target-size-mb = 4000 # The command used to initialize the swap file mkswap = mkswap {swapfile} # The command used to turn on the swap swapon = swapon {swapfile} swapoff = swapoff {swapfile}amazon-ec2-hibinit-agent-1.0.9/hibinit-agent.service000066400000000000000000000017271462620333200223110ustar00rootroot00000000000000# # Copyright 2018-2019 Amazon.com, Inc. and its affiliates. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"). You may not use this # file except in compliance with the License. A copy of the License is located at # # http://aws.amazon.com/apache2.0/ # # or in the "LICENSE" file accompanying this file. This file is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. See the License for the specific language governing permissions and # limitations under the License. [Unit] Description=Initial hibernation setup job After=cloud-config.service Wants=acpid.service [Service] Type=simple ExecStart=/usr/bin/hibinit-agent -c /etc/hibinit-config.cfg TimeoutStartSec=0 # Ensures a graceful shutdown on stop TimeoutStopSec=120 KillMode=mixed KillSignal=SIGTERM # Output needs to appear in instance console output StandardOutput=journal+console [Install] WantedBy=multi-user.target amazon-ec2-hibinit-agent-1.0.9/packaging/000077500000000000000000000000001462620333200201225ustar00rootroot00000000000000amazon-ec2-hibinit-agent-1.0.9/packaging/rhel/000077500000000000000000000000001462620333200210545ustar00rootroot00000000000000amazon-ec2-hibinit-agent-1.0.9/packaging/rhel/00-hibinit-agent.conf000066400000000000000000000012571462620333200246670ustar00rootroot00000000000000# hibinit-agent.conf file customizes and overrides the systemd configuration file in /etc/systemd/logind.conf. # Files in the *.conf.d/ configuration subdirectories are sorted by their filename in lexicographic order, # regardless of which of the # subdirectories they reside in. # If multiple files specify the same option, the entry in the file with the lexicographically latest name takes precedence. # It is recommended to prefix all filenames in those subdirectories with a two-digit number and a dash, # to simplify the ordering of the files. [Login] NAutoVTs=0 HibernateKeyIgnoreInhibited=yes SuspendKeyIgnoreInhibited=yes HandleHibernateKey=ignore HandleSuspendKey=ignore amazon-ec2-hibinit-agent-1.0.9/packaging/rhel/acpid.sleep.sh000077500000000000000000000013401462620333200236000ustar00rootroot00000000000000#!/bin/sh PATH=/sbin:/bin:/usr/bin failed='false' hibernate() { swapon /swap systemctl hibernate if [ $? -ne 0 ] then logger "Hibernation failed, Sleeping 2 mins before retry" failed='true' else failed='false' fi } case "$2" in SBTN) # The iteration had been placed here to add retry logic to hibernation # in case of failures and to avoid force stop of instances after 20min for i in 1 2 3 do hibernate if [ $failed == 'true' ]; then sleep 2m else break fi done ;; *) logger "ACPI action undefined: $2" ;; esac amazon-ec2-hibinit-agent-1.0.9/packaging/rhel/ec2-hibinit-agent.spec000066400000000000000000000131211462620333200251170ustar00rootroot00000000000000%{?python_enable_dependency_generator} %global modulenames ec2hibernatepolicy %global selinuxtype targeted %global moduletype services %global project amazon-ec2-hibinit-agent # Usage: _format var format # Expand 'modulenames' into various formats as needed # Format must contain '$x' somewhere to do anything useful %global _format() export %1=""; for x in %{modulenames}; do %1+=%2; %1+=" "; done; Name: ec2-hibinit-agent Version: 1.0.4 Release: 1%{?dist} Summary: Hibernation setup utility for Amazon EC2 License: ASL 2.0 URL: https://github.com/aws/amazon-%{name} Source0: https://github.com/aws/%{project}/archive/v%{version}/%{name}-%{version}.tar.gz BuildArch: noarch BuildRequires: systemd-rpm-macros BuildRequires: python3-devel BuildRequires: selinux-policy BuildRequires: selinux-policy-devel %{?selinux_requires} Requires: acpid Requires: grubby Requires: systemd Requires: tuned %description An EC2 agent that creates a setup for instance hibernation %prep %autosetup -n %{project}-%{version} %build %py3_build # Makefile generates pp.bz2 from .tt file. # Generating tt file https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/selinux_users_and_administrators_guide/security-enhanced_linux-the-sepolicy-suite-sepolicy_generate make -C %{_builddir}/%{project}-%{version}/packaging/rhel/ec2hibernatepolicy %install %py3_install mkdir -p %{buildroot}%{python3_sitelib} mkdir -p "%{buildroot}%{_unitdir}" mkdir -p %{buildroot}%{_sysconfdir}/acpi/events mkdir -p %{buildroot}%{_sharedstatedir}/hibinit-agent mkdir -p %{buildroot}%{_sysconfdir}/acpi/actions install -p -m 644 "%{_builddir}/%{project}-%{version}/hibinit-agent.service" %{buildroot}%{_unitdir} install -p -m 644 "%{_builddir}/%{project}-%{version}/acpid.sleep.conf" %{buildroot}%{_sysconfdir}/acpi/events/sleepconf mkdir -p %{buildroot}%{_prefix}/lib/systemd/logind.conf.d mkdir -p %{buildroot}%{_prefix}/lib/systemd/system-sleep install -p -m 644 "%{_builddir}/%{project}-%{version}/etc/hibinit-config.cfg" %{buildroot}/%{_sysconfdir}/hibinit-config.cfg install -p -m 644 "%{_builddir}/%{project}-%{version}/packaging/rhel/00-hibinit-agent.conf" %{buildroot}%{_prefix}/lib/systemd/logind.conf.d/00-hibinit-agent.conf install -p -m 755 "%{_builddir}/%{project}-%{version}/packaging/rhel/acpid.sleep.sh" %{buildroot}%{_sysconfdir}/acpi/actions/sleep.sh install -p -m 755 "%{_builddir}/%{project}-%{version}/packaging/rhel/sleep-handler.sh" %{buildroot}%{_prefix}/lib/systemd/system-sleep/sleep-handler.sh #Disable transparent huge page mkdir -p %{buildroot}%{_sysconfdir}/tuned/nothp_profile install -p -m 644 "%{_builddir}/%{project}-%{version}/packaging/rhel/tuned.conf" %{buildroot}%{_sysconfdir}/tuned/nothp_profile/tuned.conf # Install policy modules %_format MODULES $x.pp.bz2 install -d %{buildroot}%{_datadir}/selinux/packages install -m 0644 %{_builddir}/%{project}-%{version}/packaging/rhel/ec2hibernatepolicy/$MODULES \ %{buildroot}%{_datadir}/selinux/packages %files %doc README.md %license LICENSE.txt %config(noreplace) %{_sysconfdir}/hibinit-config.cfg %{_unitdir}/hibinit-agent.service %{_bindir}/hibinit-agent %config(noreplace) %{_sysconfdir}/acpi/events/sleepconf %config(noreplace) %{_sysconfdir}/acpi/actions/sleep.sh %{python3_sitelib}/ec2_hibinit_agent-*.egg-info/ %dir %{_sharedstatedir}/hibinit-agent %ghost %attr(0600,root,root) %{_sharedstatedir}/hibinit-agent/hibernation-enabled %dir %{_prefix}/lib/systemd/logind.conf.d %dir %{_prefix}/lib/systemd/system-sleep %dir %{_sysconfdir}/tuned/nothp_profile %config(noreplace) %{_sysconfdir}/tuned/nothp_profile/tuned.conf %{_prefix}/lib/systemd/system-sleep/sleep-handler.sh %{_prefix}/lib/systemd/logind.conf.d/00-hibinit-agent.conf %attr(0644,root,root) %{_datadir}/selinux/packages/*.pp.bz2 %pre %selinux_relabel_pre -s %{selinuxtype} %post %systemd_post hibinit-agent.service # # Install all modules in a single transaction # %_format MODULES %{_datadir}/selinux/packages/$x.pp.bz2 %selinux_modules_install -s %{selinuxtype} $MODULES # # Disable THP by switching to nothp_profile profile # tuned-adm profile nothp_profile %preun %systemd_preun hibinit-agent.service %postun %systemd_postun_with_restart hibinit-agent.service # # Enable THP # tuned-adm profile virtual-guest # https://fedoraproject.org/wiki/SELinux/IndependentPolicy if [ $1 -eq 0 ]; then %selinux_modules_uninstall -s %{selinuxtype} $MODULES fi %posttrans %selinux_relabel_post -s %{selinuxtype} %changelog * Thu Jan 14 2021 Mohamed Aboubakr - 1.0.4-1 - Call grub2-mkconfig in hibernate agent before calling grubby * Tue Nov 03 2020 Mohamed Aboubakr - 1.0.3-3 - Moving selinux folder in packaging directory. - Use make file to generate .pp.bz2 file * Fri Oct 02 2020 David Duncan - 1.0.3-2 - Modify Spec for build requirements * Thu Aug 13 2020 Mohamed Aboubakr - 1.0.3-1 - Support Redhat and Fedora by adding sepolicy - Ignore handle hibernation in systemd configuration * Fri Jan 24 2020 Frederick Lefebvre - 1.0.1-2 - Restart the hibinit-agent service on upgrade * Thu Jan 23 2020 Frederick Lefebvre - 1.0.1-1 - Added IMDSv2 support - Renamed spec file to match the actual package name * Fri Jun 14 2019 Anchal Agarwal - 1.0.0-4 - Added hibernation re-try logic in case of hibernation failure * Wed Nov 07 2018 Matt Dees - 1.0.0-2 - Clean up hibernation configured check * Wed Oct 31 2018 Anchal Agarwal - 1.0.0-1 - Initial build amazon-ec2-hibinit-agent-1.0.9/packaging/rhel/ec2hibernatepolicy/000077500000000000000000000000001462620333200246275ustar00rootroot00000000000000amazon-ec2-hibinit-agent-1.0.9/packaging/rhel/ec2hibernatepolicy/Makefile000066400000000000000000000011431462620333200262660ustar00rootroot00000000000000TARGET?=ec2hibernatepolicy MODULES?=${TARGET:=.pp.bz2} SHAREDIR?=/usr/share SELINUXTYPE?=targeted all: ${TARGET:=.pp.bz2} %.pp.bz2: %.pp @echo Compressing $^ -\> $@ bzip2 -9 $^ %.pp: %.te make -f ${SHAREDIR}/selinux/devel/Makefile $@ clean: rm -f *~ *.tc *.pp *.pp.bz2 rm -rf tmp *.tar.gz man: install-policy sepolicy manpage --path . --domain ${TARGET}_t install-policy: all semodule -i ${TARGET}.pp.bz2 install: man install -D -m 644 ${TARGET}.pp.bz2 ${DESTDIR}${SHAREDIR}/selinux/packages/${SELINUXTYPE}/${TARGET}.pp.bz2 install -D -m 644 ${TARGET}_selinux.8 ${DESTDIR}${SHAREDIR}/man/man8/ amazon-ec2-hibinit-agent-1.0.9/packaging/rhel/ec2hibernatepolicy/ec2hibernatepolicy.te000066400000000000000000000011121462620333200307270ustar00rootroot00000000000000 module ec2hibernatepolicy 1.0; require { type init_t; type swapfile_t; type systemd_logind_t; class file { getattr ioctl open read }; } #============= init_t ============== allow init_t swapfile_t:file ioctl; #!!!! This avc is allowed in the current policy allow init_t swapfile_t:file { open read ioctl }; #============= systemd_logind_t ============== #!!!! This avc is allowed in the current policy #!!!! This av rule may have been overridden by an extended permission av rule allow systemd_logind_t swapfile_t:file { getattr ioctl open read }; amazon-ec2-hibinit-agent-1.0.9/packaging/rhel/sleep-handler.sh000077500000000000000000000005421462620333200241370ustar00rootroot00000000000000#!/bin/bash # This is called before hibernating or after resuming, as follows: # $0=/usr/lib/systemd/system-sleep/sleepyhead, $1=pre, $2=suspend # ...and when the lid is opened, as follows: # $0=/usr/lib/systemd/system-sleep/sleepyhead, $1=post, $2=suspend if [ "$1" = "post" ] ; then logger "Resuming from sleep to swapoff" swapoff /swap fi amazon-ec2-hibinit-agent-1.0.9/packaging/rhel/tuned.conf000066400000000000000000000000771462620333200230460ustar00rootroot00000000000000[main] include=virtual-guest [vm] transparent_hugepages=never amazon-ec2-hibinit-agent-1.0.9/packaging/sles/000077500000000000000000000000001462620333200210705ustar00rootroot00000000000000amazon-ec2-hibinit-agent-1.0.9/packaging/sles/ec2-hibernate-linux-agent.changes000066400000000000000000000021561462620333200272670ustar00rootroot00000000000000------------------------------------------------------------------- Tue Jul 12 12:46:18 UTC 2021 - Mohamed Aboubakr - Support EC2 Hibernate in Suse Linux Enterprise Server. + Call grub2-mkconfig in hibernate agent before calling grubby + Moving selinux folder in packaging directory. + Use make file to generate .pp.bz2 file + Modify Spec for build requirements ------------------------------------------------------------------- Fri Jan 4 12:46:18 UTC 2019 - John Paul Adrian Glaubitz - Add patch to override hibernate command with 'systemctl hibernate' + ehla_override-hibernate-command.patch ------------------------------------------------------------------- Tue Oct 23 10:18:31 UTC 2018 - John Paul Adrian Glaubitz - Initial release (bsc#1098305, bsc#1111755) + Version 1.0.0 - Include custom systemd service file for agent + ec2-hibernate-linux-agent.service - Include patch to handle missing grub-legacy installation + ehla_handle-missing-grub-legacy.patch - Exclude SysVInit setup script for agent + enable-ec2-spot-hibernation amazon-ec2-hibinit-agent-1.0.9/packaging/sles/ec2-hibernate-linux-agent.spec000066400000000000000000000115721462620333200266130ustar00rootroot00000000000000# # spec file for ec2-hibernate-linux-agent # # Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed # upon. The license for this file, and modifications and additions to the # file, is the same license as for the pristine package itself (unless the # license for the pristine package is not an Open Source License, in which # case the license is the MIT License). An "Open Source License" is a # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. # Please submit bugfixes or comments via http://bugs.opensuse.org/ # %{?python_enable_dependency_generator} %global project amazon-ec2-hibinit-agent # Usage: _format var format # Expand 'modulenames' into various formats as needed # Format must contain '$x' somewhere to do anything useful %global _format() export %1=""; for x in %{modulenames}; do %1+=%2; %1+=" "; done; Name: ec2-hibernate-linux-agent Version: 1.0.4 Release: 1%{?dist} Summary: Hibernating Agent for Linux on Amazon EC2 Group: System/Management License: MIT URL: https://github.com/aws/%{project} Source0: https://github.com/aws/%{project}/archive/v%{version}/ec2-hibinit-agent-%{version}.tar.gz BuildArch: noarch BuildRequires: systemd-rpm-macros BuildRequires: python3-devel BuildRequires: pkgconfig(systemd) BuildRequires: python-rpm-generators BuildRequires: tuned BuildRequires: bzip2 Requires: acpid Requires: grubby Requires: systemd Requires: tuned %description Hibernating Agent for Linux on Amazon EC2 This agent does several things: 1. Upon startup it checks for sufficient swap space to allow hibernate and fails if it's present but there's not enough of it. 2. If there's no swap space, it creates it and launches a background thread to touch all of its blocks to make sure that EBS volumes are pre-warmed. 3. It updates the offset of the swap file in the kernel using SNAPSHOT_SET_SWAP_AREA ioctl. 4. It daemonizes and starts a polling thread to listen for instance termination notifications. %prep %autosetup -n %{project}-%{version} %build %py3_build %install %py3_install --root %{buildroot} mkdir -p %{buildroot}%{python3_sitelib} mkdir -p "%{buildroot}%{_unitdir}" mkdir -p %{buildroot}%{_sysconfdir}/acpi/events mkdir -p %{buildroot}%{_sharedstatedir}/hibinit-agent mkdir -p %{buildroot}%{_sysconfdir}/acpi/actions mkdir -p %{buildroot}%{_sbindir} install -p -m 644 "%{_builddir}/%{project}-%{version}/hibinit-agent.service" %{buildroot}%{_unitdir} install -p -m 644 "%{_builddir}/%{project}-%{version}/acpid.sleep.conf" %{buildroot}%{_sysconfdir}/acpi/events/sleepconf mkdir -p %{buildroot}%{_prefix}/lib/systemd/logind.conf.d mkdir -p %{buildroot}%{_prefix}/lib/systemd/system-sleep install -p -m 644 "%{_builddir}/%{project}-%{version}/etc/hibinit-config.cfg" %{buildroot}/%{_sysconfdir}/hibinit-config.cfg install -p -m 644 "%{_builddir}/%{project}-%{version}/packaging/rhel/00-hibinit-agent.conf" %{buildroot}%{_prefix}/lib/systemd/logind.conf.d/00-hibinit-agent.conf install -p -m 755 "%{_builddir}/%{project}-%{version}/packaging/rhel/acpid.sleep.sh" %{buildroot}%{_sysconfdir}/acpi/actions/sleep.sh install -p -m 755 "%{_builddir}/%{project}-%{version}/packaging/rhel/sleep-handler.sh" %{buildroot}%{_prefix}/lib/systemd/system-sleep/sleep-handler.sh #Disable transparent huge page mkdir -p %{buildroot}%{_sysconfdir}/tuned/nothp_profile install -p -m 644 "%{_builddir}/%{project}-%{version}/packaging/rhel/tuned.conf" %{buildroot}%{_sysconfdir}/tuned/nothp_profile/tuned.conf ln -sf %{_sbindir}/service %{buildroot}%{_sbindir}/rchibinit-agent %files %doc README.md %license LICENSE.txt %config(noreplace) %{_sysconfdir}/hibinit-config.cfg %{_unitdir}/hibinit-agent.service %{_bindir}/hibinit-agent %{_sbindir}/rchibinit-agent %config(noreplace) %{_sysconfdir}/acpi/events/sleepconf %config(noreplace) %{_sysconfdir}/acpi/actions/sleep.sh %{python3_sitelib}/ec2_hibinit_agent-*.egg-info/ %dir %{_sharedstatedir}/hibinit-agent %ghost %attr(0600,root,root) %{_sharedstatedir}/hibinit-agent/hibernation-enabled %dir %{_prefix}/lib/systemd/logind.conf.d %dir %{_prefix}/lib/systemd/system-sleep %dir %{_sysconfdir}/acpi %dir %{_sysconfdir}/acpi/events %dir %{_sysconfdir}/acpi/actions %dir %{_sysconfdir}/tuned/nothp_profile %config(noreplace) %{_sysconfdir}/tuned/nothp_profile/tuned.conf %{_prefix}/lib/systemd/system-sleep/sleep-handler.sh %{_prefix}/lib/systemd/logind.conf.d/00-hibinit-agent.conf %pre %service_add_pre hibinit-agent.service %post %service_add_post hibinit-agent.service # # Disable THP by switching to nothp_profile profile # tuned-adm profile nothp_profile %preun %service_del_preun hibinit-agent.service %postun %systemd_postun_with_restart hibinit-agent.service %changelog amazon-ec2-hibinit-agent-1.0.9/setup.py000066400000000000000000000013161462620333200177110ustar00rootroot00000000000000#!/usr/bin/python try: from setuptools import setup except ImportError: from distutils.core import setup hib_classifiers = [ "License :: OSI Approved :: APACHE SOFTWARE LICENSE", "Topic :: Utilities", ] with open("README.md", "r") as fp: hib_long_description = fp.read() setup(name="ec2-hibinit-agent", version='1.0.9', author="Anchal Agarwal", author_email="anchalag@amazon.com", tests_require=["pytest"], scripts=['agent/hibinit-agent'], data_files=[('/etc', ['etc/hibinit-config.cfg'])], description="Hibernation setup for EC2 Instances", long_description=hib_long_description, license="Apache 2.0", classifiers=hib_classifiers )