1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 cfg = config.virtualisation.azure.agent;
8
9 waagent = with pkgs; stdenv.mkDerivation rec {
10 name = "waagent-2.0";
11 src = pkgs.fetchFromGitHub {
12 owner = "Azure";
13 repo = "WALinuxAgent";
14 rev = "1b3a8407a95344d9d12a2a377f64140975f1e8e4";
15 sha256 = "10byzvmpgrmr4d5mdn2kq04aapqb3sgr1admk13wjmy5cd6bwd2x";
16 };
17
18 patches = [ ./azure-agent-entropy.patch ];
19
20 buildInputs = [ makeWrapper python pythonPackages.wrapPython ];
21 runtimeDeps = [ findutils gnugrep gawk coreutils openssl openssh
22 nettools # for hostname
23 procps # for pidof
24 shadow # for useradd, usermod
25 utillinux # for (u)mount, fdisk, sfdisk, mkswap
26 parted
27 ];
28 pythonPath = [ pythonPackages.pyasn1 ];
29
30 configurePhase = false;
31 buildPhase = false;
32
33 installPhase = ''
34 substituteInPlace config/99-azure-product-uuid.rules \
35 --replace /bin/chmod "${coreutils}/bin/chmod"
36 mkdir -p $out/lib/udev/rules.d
37 cp config/*.rules $out/lib/udev/rules.d
38
39 mkdir -p $out/bin
40 cp waagent $out/bin/
41 chmod +x $out/bin/waagent
42
43 wrapProgram "$out/bin/waagent" \
44 --prefix PYTHONPATH : $PYTHONPATH \
45 --prefix PATH : "${makeBinPath runtimeDeps}"
46 '';
47 };
48
49 provisionedHook = pkgs.writeScript "provisioned-hook" ''
50 #!${pkgs.stdenv.shell}
51 ${config.systemd.package}/bin/systemctl start provisioned.target
52 '';
53
54in
55
56{
57
58 ###### interface
59
60 options.virtualisation.azure.agent = {
61 enable = mkOption {
62 default = false;
63 description = "Whether to enable the Windows Azure Linux Agent.";
64 };
65 verboseLogging = mkOption {
66 default = false;
67 description = "Whether to enable verbose logging.";
68 };
69 };
70
71 ###### implementation
72
73 config = mkIf cfg.enable {
74 assertions = [ {
75 assertion = pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64;
76 message = "Azure not currently supported on ${pkgs.stdenv.system}";
77 } {
78 assertion = config.networking.networkmanager.enable == false;
79 message = "Windows Azure Linux Agent is not compatible with NetworkManager";
80 } ];
81
82 boot.initrd.kernelModules = [ "ata_piix" ];
83 networking.firewall.allowedUDPPorts = [ 68 ];
84
85
86 environment.etc."waagent.conf".text = ''
87 #
88 # Windows Azure Linux Agent Configuration
89 #
90
91 Role.StateConsumer=${provisionedHook}
92
93 # Enable instance creation
94 Provisioning.Enabled=y
95
96 # Password authentication for root account will be unavailable.
97 Provisioning.DeleteRootPassword=n
98
99 # Generate fresh host key pair.
100 Provisioning.RegenerateSshHostKeyPair=n
101
102 # Supported values are "rsa", "dsa" and "ecdsa".
103 Provisioning.SshHostKeyPairType=ed25519
104
105 # Monitor host name changes and publish changes via DHCP requests.
106 Provisioning.MonitorHostName=y
107
108 # Decode CustomData from Base64.
109 Provisioning.DecodeCustomData=n
110
111 # Execute CustomData after provisioning.
112 Provisioning.ExecuteCustomData=n
113
114 # Format if unformatted. If 'n', resource disk will not be mounted.
115 ResourceDisk.Format=y
116
117 # File system on the resource disk
118 # Typically ext3 or ext4. FreeBSD images should use 'ufs2' here.
119 ResourceDisk.Filesystem=ext4
120
121 # Mount point for the resource disk
122 ResourceDisk.MountPoint=/mnt/resource
123
124 # Respond to load balancer probes if requested by Windows Azure.
125 LBProbeResponder=y
126
127 # Enable logging to serial console (y|n)
128 # When stdout is not enough...
129 # 'y' if not set
130 Logs.Console=y
131
132 # Enable verbose logging (y|n)
133 Logs.Verbose=${if cfg.verboseLogging then "y" else "n"}
134
135 # Root device timeout in seconds.
136 OS.RootDeviceScsiTimeout=300
137 '';
138
139 services.udev.packages = [ waagent ];
140
141 networking.dhcpcd.persistent = true;
142
143 services.logrotate = {
144 enable = true;
145 config = ''
146 /var/log/waagent.log {
147 compress
148 monthly
149 rotate 6
150 notifempty
151 missingok
152 }
153 '';
154 };
155
156 systemd.targets.provisioned = {
157 description = "Services Requiring Azure VM provisioning to have finished";
158 };
159
160 systemd.services.consume-hypervisor-entropy =
161 { description = "Consume entropy in ACPI table provided by Hyper-V";
162
163 wantedBy = [ "sshd.service" "waagent.service" ];
164 before = [ "sshd.service" "waagent.service" ];
165 after = [ "local-fs.target" ];
166
167 path = [ pkgs.coreutils ];
168 script =
169 ''
170 echo "Fetching entropy..."
171 cat /sys/firmware/acpi/tables/OEM0 > /dev/random
172 '';
173 serviceConfig.Type = "oneshot";
174 serviceConfig.RemainAfterExit = true;
175 serviceConfig.StandardError = "journal+console";
176 serviceConfig.StandardOutput = "journal+console";
177 };
178
179 systemd.services.waagent = {
180 wantedBy = [ "multi-user.target" ];
181 after = [ "ip-up.target" "sshd.service" ];
182
183 path = [ pkgs.e2fsprogs ];
184 description = "Windows Azure Agent Service";
185 unitConfig.ConditionPathExists = "/etc/waagent.conf";
186 serviceConfig = {
187 ExecStart = "${waagent}/bin/waagent -daemon";
188 Type = "simple";
189 };
190 };
191
192 };
193
194}