1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6 cfg = config.services.flannel;
7
8 networkConfig = filterAttrs (n: v: v != null) {
9 Network = cfg.network;
10 SubnetLen = cfg.subnetLen;
11 SubnetMin = cfg.subnetMin;
12 SubnetMax = cfg.subnetMax;
13 Backend = cfg.backend;
14 };
15in {
16 options.services.flannel = {
17 enable = mkEnableOption "flannel";
18
19 package = mkPackageOption pkgs "flannel" { };
20
21 publicIp = mkOption {
22 description = ''
23 IP accessible by other nodes for inter-host communication.
24 Defaults to the IP of the interface being used for communication.
25 '';
26 type = types.nullOr types.str;
27 default = null;
28 };
29
30 iface = mkOption {
31 description = ''
32 Interface to use (IP or name) for inter-host communication.
33 Defaults to the interface for the default route on the machine.
34 '';
35 type = types.nullOr types.str;
36 default = null;
37 };
38
39 etcd = {
40 endpoints = mkOption {
41 description = "Etcd endpoints";
42 type = types.listOf types.str;
43 default = ["http://127.0.0.1:2379"];
44 };
45
46 prefix = mkOption {
47 description = "Etcd key prefix";
48 type = types.str;
49 default = "/coreos.com/network";
50 };
51
52 caFile = mkOption {
53 description = "Etcd certificate authority file";
54 type = types.nullOr types.path;
55 default = null;
56 };
57
58 certFile = mkOption {
59 description = "Etcd cert file";
60 type = types.nullOr types.path;
61 default = null;
62 };
63
64 keyFile = mkOption {
65 description = "Etcd key file";
66 type = types.nullOr types.path;
67 default = null;
68 };
69 };
70
71 kubeconfig = mkOption {
72 description = ''
73 Path to kubeconfig to use for storing flannel config using the
74 Kubernetes API
75 '';
76 type = types.nullOr types.path;
77 default = null;
78 };
79
80 network = mkOption {
81 description = " IPv4 network in CIDR format to use for the entire flannel network.";
82 type = types.str;
83 };
84
85 nodeName = mkOption {
86 description = ''
87 Needed when running with Kubernetes as backend as this cannot be auto-detected";
88 '';
89 type = types.nullOr types.str;
90 default = config.networking.fqdnOrHostName;
91 defaultText = literalExpression "config.networking.fqdnOrHostName";
92 example = "node1.example.com";
93 };
94
95 storageBackend = mkOption {
96 description = "Determines where flannel stores its configuration at runtime";
97 type = types.enum ["etcd" "kubernetes"];
98 default = "etcd";
99 };
100
101 subnetLen = mkOption {
102 description = ''
103 The size of the subnet allocated to each host. Defaults to 24 (i.e. /24)
104 unless the Network was configured to be smaller than a /24 in which case
105 it is one less than the network.
106 '';
107 type = types.int;
108 default = 24;
109 };
110
111 subnetMin = mkOption {
112 description = ''
113 The beginning of IP range which the subnet allocation should start with.
114 Defaults to the first subnet of Network.
115 '';
116 type = types.nullOr types.str;
117 default = null;
118 };
119
120 subnetMax = mkOption {
121 description = ''
122 The end of IP range which the subnet allocation should start with.
123 Defaults to the last subnet of Network.
124 '';
125 type = types.nullOr types.str;
126 default = null;
127 };
128
129 backend = mkOption {
130 description = "Type of backend to use and specific configurations for that backend.";
131 type = types.attrs;
132 default = {
133 Type = "vxlan";
134 };
135 };
136 };
137
138 config = mkIf cfg.enable {
139 systemd.services.flannel = {
140 description = "Flannel Service";
141 wantedBy = [ "multi-user.target" ];
142 after = [ "network.target" ];
143 environment = {
144 FLANNELD_PUBLIC_IP = cfg.publicIp;
145 FLANNELD_IFACE = cfg.iface;
146 } // optionalAttrs (cfg.storageBackend == "etcd") {
147 FLANNELD_ETCD_ENDPOINTS = concatStringsSep "," cfg.etcd.endpoints;
148 FLANNELD_ETCD_KEYFILE = cfg.etcd.keyFile;
149 FLANNELD_ETCD_CERTFILE = cfg.etcd.certFile;
150 FLANNELD_ETCD_CAFILE = cfg.etcd.caFile;
151 ETCDCTL_CERT = cfg.etcd.certFile;
152 ETCDCTL_KEY = cfg.etcd.keyFile;
153 ETCDCTL_CACERT = cfg.etcd.caFile;
154 ETCDCTL_ENDPOINTS = concatStringsSep "," cfg.etcd.endpoints;
155 ETCDCTL_API = "3";
156 } // optionalAttrs (cfg.storageBackend == "kubernetes") {
157 FLANNELD_KUBE_SUBNET_MGR = "true";
158 FLANNELD_KUBECONFIG_FILE = cfg.kubeconfig;
159 NODE_NAME = cfg.nodeName;
160 };
161 path = [ pkgs.iptables ];
162 preStart = optionalString (cfg.storageBackend == "etcd") ''
163 echo "setting network configuration"
164 until ${pkgs.etcd}/bin/etcdctl put /coreos.com/network/config '${builtins.toJSON networkConfig}'
165 do
166 echo "setting network configuration, retry"
167 sleep 1
168 done
169 '';
170 serviceConfig = {
171 ExecStart = "${cfg.package}/bin/flannel";
172 Restart = "always";
173 RestartSec = "10s";
174 RuntimeDirectory = "flannel";
175 };
176 };
177
178 services.etcd.enable = mkDefault (cfg.storageBackend == "etcd" && cfg.etcd.endpoints == ["http://127.0.0.1:2379"]);
179
180 # for some reason, flannel doesn't let you configure this path
181 # see: https://github.com/coreos/flannel/blob/master/Documentation/configuration.md#configuration
182 environment.etc."kube-flannel/net-conf.json" = mkIf (cfg.storageBackend == "kubernetes") {
183 source = pkgs.writeText "net-conf.json" (builtins.toJSON networkConfig);
184 };
185 };
186}