1{ config, lib, pkgs, ... }:
2
3with lib; with import ./common.nix {inherit lib;};
4
5let
6 cfg = config.virtualisation.openstack.glance;
7 commonConf = ''
8 [database]
9 connection = "mysql://${cfg.database.user}:${cfg.database.password.pattern}@${cfg.database.host}/${cfg.database.name}"
10 notification_driver = noop
11
12 [keystone_authtoken]
13 auth_url = ${cfg.authUrl}
14 auth_plugin = password
15 project_name = service
16 project_domain_id = default
17 user_domain_id = default
18 username = ${cfg.serviceUsername}
19 password = ${cfg.servicePassword.pattern}
20
21 [glance_store]
22 default_store = file
23 filesystem_store_datadir = /var/lib/glance/images/
24 '';
25 glanceApiConfTpl = pkgs.writeText "glance-api.conf" ''
26 ${commonConf}
27
28 [paste_deploy]
29 flavor = keystone
30 config_file = ${cfg.package}/etc/glance-api-paste.ini
31 '';
32 glanceRegistryConfTpl = pkgs.writeText "glance-registry.conf" ''
33 ${commonConf}
34
35 [paste_deploy]
36 config_file = ${cfg.package}/etc/glance-registry-paste.ini
37 '';
38 glanceApiConf = "/var/lib/glance/glance-api.conf";
39 glanceRegistryConf = "/var/lib/glance/glance-registry.conf";
40
41in {
42 options.virtualisation.openstack.glance = {
43 package = mkOption {
44 type = types.package;
45 default = pkgs.glance;
46 defaultText = "pkgs.glance";
47 description = ''
48 Glance package to use.
49 '';
50 };
51
52 enable = mkOption {
53 default = false;
54 type = types.bool;
55 description = ''
56 This option enables Glance as a single-machine
57 installation. That is, all of Glance's components are
58 enabled on this machine. This is useful for evaluating and
59 experimenting with Glance. Note we are currently not
60 providing any configurations for a multi-node setup.
61 '';
62 };
63
64 authUrl = mkOption {
65 type = types.str;
66 default = http://localhost:5000;
67 description = ''
68 Complete public Identity (Keystone) API endpoint. Note this is
69 unversionned.
70 '';
71 };
72
73 serviceUsername = mkOption {
74 type = types.str;
75 default = "glance";
76 description = ''
77 The Glance service username. This user is created if bootstrap
78 is enable, otherwise it has to be manually created before
79 starting this service.
80 '';
81 };
82
83 servicePassword = mkSecretOption {
84 name = "glanceAdminPassword";
85 description = ''
86 The Glance service user's password.
87 '';
88 };
89
90 database = databaseOption "glance";
91
92 bootstrap = {
93 enable = mkOption {
94 default = false;
95 type = types.bool;
96 description = ''
97 Bootstrap the Glance service by creating the service tenant,
98 an admin account and a public endpoint. This option provides
99 a ready-to-use glance service. This is only done at the
100 first Glance execution by the systemd post start section.
101 The keystone admin account is used to create required
102 Keystone resource for the Glance service.
103
104 <note><para> This option is a helper for setting up
105 development or testing environments.</para></note>
106 '';
107 };
108
109 endpointPublic = mkOption {
110 type = types.str;
111 default = "http://localhost:9292";
112 description = ''
113 The public image endpoint. The link <link
114 xlink:href="http://docs.openstack.org/liberty/install-guide-rdo/keystone-services.html">
115 create endpoint</link> provides more informations
116 about that.
117 '';
118 };
119
120 keystoneAdminUsername = mkOption {
121 type = types.str;
122 default = "admin";
123 description = ''
124 The keystone admin user name used to create the Glance account.
125 '';
126 };
127
128 keystoneAdminPassword = mkSecretOption {
129 name = "keystoneAdminPassword";
130 description = ''
131 The keystone admin user's password.
132 '';
133 };
134
135 keystoneAdminTenant = mkOption {
136 type = types.str;
137 default = "admin";
138 description = ''
139 The keystone admin tenant used to create the Glance account.
140 '';
141 };
142 keystoneAuthUrl = mkOption {
143 type = types.str;
144 default = "http://localhost:5000/v2.0";
145 description = ''
146 The keystone auth url used to create the Glance account.
147 '';
148 };
149 };
150 };
151
152 config = mkIf cfg.enable {
153 users.extraUsers = [{
154 name = "glance";
155 group = "glance";
156 uid = config.ids.gids.glance;
157
158 }];
159 users.extraGroups = [{
160 name = "glance";
161 gid = config.ids.gids.glance;
162 }];
163
164 systemd.services.glance-registry = {
165 description = "OpenStack Glance Registry Daemon";
166 after = [ "network.target"];
167 path = [ pkgs.curl pkgs.pythonPackages.keystoneclient pkgs.gawk ];
168 wantedBy = [ "multi-user.target" ];
169 preStart = ''
170 mkdir -m 775 -p /var/lib/glance/{images,scrubber,image_cache}
171 chown glance:glance /var/lib/glance/{images,scrubber,image_cache}
172
173 # Secret file managment
174 cp ${glanceRegistryConfTpl} ${glanceRegistryConf};
175 chown glance:glance ${glanceRegistryConf};
176 chmod 640 ${glanceRegistryConf}
177 ${replaceSecret cfg.database.password glanceRegistryConf}
178 ${replaceSecret cfg.servicePassword glanceRegistryConf}
179
180 cp ${glanceApiConfTpl} ${glanceApiConf};
181 chown glance:glance ${glanceApiConf};
182 chmod 640 ${glanceApiConf}
183 ${replaceSecret cfg.database.password glanceApiConf}
184 ${replaceSecret cfg.servicePassword glanceApiConf}
185
186 # Initialise the database
187 ${cfg.package}/bin/glance-manage --config-file=${glanceApiConf} --config-file=${glanceRegistryConf} db_sync
188 '';
189 postStart = ''
190 set -eu
191 export OS_AUTH_URL=${cfg.bootstrap.keystoneAuthUrl}
192 export OS_USERNAME=${cfg.bootstrap.keystoneAdminUsername}
193 export OS_PASSWORD=${getSecret cfg.bootstrap.keystoneAdminPassword}
194 export OS_TENANT_NAME=${cfg.bootstrap.keystoneAdminTenant}
195
196 # Wait until the keystone is available for use
197 count=0
198 while ! keystone user-get ${cfg.bootstrap.keystoneAdminUsername} > /dev/null
199 do
200 if [ $count -eq 30 ]
201 then
202 echo "Tried 30 times, giving up..."
203 exit 1
204 fi
205
206 echo "Keystone not yet started. Waiting for 1 second..."
207 count=$((count++))
208 sleep 1
209 done
210
211 # If the service glance doesn't exist, we consider glance is
212 # not initialized
213 if ! keystone service-get glance
214 then
215 keystone service-create --type image --name glance
216 ID=$(keystone service-get glance | awk '/ id / { print $4 }')
217 keystone endpoint-create --region RegionOne --service $ID --internalurl http://localhost:9292 --adminurl http://localhost:9292 --publicurl ${cfg.bootstrap.endpointPublic}
218
219 keystone user-create --name ${cfg.serviceUsername} --tenant service --pass ${getSecret cfg.servicePassword}
220 keystone user-role-add --tenant service --user ${cfg.serviceUsername} --role admin
221 fi
222 '';
223 serviceConfig = {
224 PermissionsStartOnly = true; # preStart must be run as root
225 TimeoutStartSec = "600"; # 10min for initial db migrations
226 User = "glance";
227 Group = "glance";
228 ExecStart = "${cfg.package}/bin/glance-registry --config-file=${glanceRegistryConf}";
229 };
230 };
231 systemd.services.glance-api = {
232 description = "OpenStack Glance API Daemon";
233 after = [ "glance-registry.service" "network.target"];
234 requires = [ "glance-registry.service" "network.target"];
235 wantedBy = [ "multi-user.target" ];
236 serviceConfig = {
237 PermissionsStartOnly = true; # preStart must be run as root
238 User = "glance";
239 Group = "glance";
240 ExecStart = "${cfg.package}/bin/glance-api --config-file=${glanceApiConf}";
241 };
242 };
243 };
244
245}