1{
2 config,
3 pkgs,
4 lib,
5 ...
6}:
7let
8 cfg = config.services.lifecycled;
9
10 # TODO: Add the ability to extend this with an rfc 42-like interface.
11 # In the meantime, one can modify the environment (as
12 # long as it's not overriding anything from here) with
13 # systemd.services.lifecycled.serviceConfig.Environment
14 configFile = pkgs.writeText "lifecycled" ''
15 LIFECYCLED_HANDLER=${cfg.handler}
16 ${lib.optionalString (
17 cfg.cloudwatchGroup != null
18 ) "LIFECYCLED_CLOUDWATCH_GROUP=${cfg.cloudwatchGroup}"}
19 ${lib.optionalString (
20 cfg.cloudwatchStream != null
21 ) "LIFECYCLED_CLOUDWATCH_STREAM=${cfg.cloudwatchStream}"}
22 ${lib.optionalString cfg.debug "LIFECYCLED_DEBUG=${lib.boolToString cfg.debug}"}
23 ${lib.optionalString (cfg.instanceId != null) "LIFECYCLED_INSTANCE_ID=${cfg.instanceId}"}
24 ${lib.optionalString cfg.json "LIFECYCLED_JSON=${lib.boolToString cfg.json}"}
25 ${lib.optionalString cfg.noSpot "LIFECYCLED_NO_SPOT=${lib.boolToString cfg.noSpot}"}
26 ${lib.optionalString (cfg.snsTopic != null) "LIFECYCLED_SNS_TOPIC=${cfg.snsTopic}"}
27 ${lib.optionalString (cfg.awsRegion != null) "AWS_REGION=${cfg.awsRegion}"}
28 '';
29in
30{
31 meta.maintainers = with lib.maintainers; [
32 cole-h
33 grahamc
34 ];
35
36 options = {
37 services.lifecycled = {
38 enable = lib.mkEnableOption "lifecycled, a daemon for responding to AWS AutoScaling Lifecycle Hooks";
39
40 queueCleaner = {
41 enable = lib.mkEnableOption "lifecycled-queue-cleaner";
42
43 frequency = lib.mkOption {
44 type = lib.types.str;
45 default = "hourly";
46 description = ''
47 How often to trigger the queue cleaner.
48
49 NOTE: This string should be a valid value for a systemd
50 timer's `OnCalendar` configuration. See
51 {manpage}`systemd.timer(5)`
52 for more information.
53 '';
54 };
55
56 parallel = lib.mkOption {
57 type = lib.types.ints.unsigned;
58 default = 20;
59 description = ''
60 The number of parallel deletes to run.
61 '';
62 };
63 };
64
65 instanceId = lib.mkOption {
66 type = lib.types.nullOr lib.types.str;
67 default = null;
68 description = ''
69 The instance ID to listen for events for.
70 '';
71 };
72
73 snsTopic = lib.mkOption {
74 type = lib.types.nullOr lib.types.str;
75 default = null;
76 description = ''
77 The SNS topic that receives events.
78 '';
79 };
80
81 noSpot = lib.mkOption {
82 type = lib.types.bool;
83 default = false;
84 description = ''
85 Disable the spot termination listener.
86 '';
87 };
88
89 handler = lib.mkOption {
90 type = lib.types.path;
91 description = ''
92 The script to invoke to handle events.
93 '';
94 };
95
96 json = lib.mkOption {
97 type = lib.types.bool;
98 default = false;
99 description = ''
100 Enable JSON logging.
101 '';
102 };
103
104 cloudwatchGroup = lib.mkOption {
105 type = lib.types.nullOr lib.types.str;
106 default = null;
107 description = ''
108 Write logs to a specific Cloudwatch Logs group.
109 '';
110 };
111
112 cloudwatchStream = lib.mkOption {
113 type = lib.types.nullOr lib.types.str;
114 default = null;
115 description = ''
116 Write logs to a specific Cloudwatch Logs stream. Defaults to the instance ID.
117 '';
118 };
119
120 debug = lib.mkOption {
121 type = lib.types.bool;
122 default = false;
123 description = ''
124 Enable debugging information.
125 '';
126 };
127
128 # XXX: Can be removed if / when
129 # https://github.com/buildkite/lifecycled/pull/91 is merged.
130 awsRegion = lib.mkOption {
131 type = lib.types.nullOr lib.types.str;
132 default = null;
133 description = ''
134 The region used for accessing AWS services.
135 '';
136 };
137 };
138 };
139
140 ### Implementation ###
141
142 config = lib.mkMerge [
143 (lib.mkIf cfg.enable {
144 environment.etc."lifecycled".source = configFile;
145
146 systemd.packages = [ pkgs.lifecycled ];
147 systemd.services.lifecycled = {
148 wantedBy = [ "network-online.target" ];
149 restartTriggers = [ configFile ];
150 };
151 })
152
153 (lib.mkIf cfg.queueCleaner.enable {
154 systemd.services.lifecycled-queue-cleaner = {
155 description = "Lifecycle Daemon Queue Cleaner";
156 environment = lib.optionalAttrs (cfg.awsRegion != null) { AWS_REGION = cfg.awsRegion; };
157 serviceConfig = {
158 Type = "oneshot";
159 ExecStart = "${pkgs.lifecycled}/bin/lifecycled-queue-cleaner -parallel ${toString cfg.queueCleaner.parallel}";
160 };
161 };
162
163 systemd.timers.lifecycled-queue-cleaner = {
164 description = "Lifecycle Daemon Queue Cleaner Timer";
165 wantedBy = [ "timers.target" ];
166 after = [ "network-online.target" ];
167 timerConfig = {
168 Unit = "lifecycled-queue-cleaner.service";
169 OnCalendar = "${cfg.queueCleaner.frequency}";
170 };
171 };
172 })
173 ];
174}