diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index eb6f8e70689..6ab4b24a349 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -281,6 +281,7 @@ riak-cs = 263; infinoted = 264; keystone = 265; + glance = 266; # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399! @@ -532,6 +533,7 @@ riak-cs = 263; infinoted = 264; keystone = 265; + glance = 266; # When adding a gid, make sure it doesn't match an existing # uid. Users and groups with the same name should have equal diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index cd12fe4f9b3..aa1ec0df018 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -632,4 +632,5 @@ ./virtualisation/xen-dom0.nix ./virtualisation/xe-guest-utilities.nix ./virtualisation/openstack/keystone.nix + ./virtualisation/openstack/glance.nix ] diff --git a/nixos/modules/virtualisation/openstack/common.nix b/nixos/modules/virtualisation/openstack/common.nix index 3fce54a2fa5..2feb0a87395 100644 --- a/nixos/modules/virtualisation/openstack/common.nix +++ b/nixos/modules/virtualisation/openstack/common.nix @@ -51,4 +51,34 @@ rec { }; };}); }; + + databaseOption = name: { + host = mkOption { + type = types.str; + default = "localhost"; + description = '' + Host of the database. + ''; + }; + + name = mkOption { + type = types.str; + default = name; + description = '' + Name of the existing database. + ''; + }; + + user = mkOption { + type = types.str; + default = name; + description = '' + The database user. The user must exist and has access to + the specified database. + ''; + }; + password = mkSecretOption { + name = name + "MysqlPassword"; + description = "The database user's password";}; + }; } diff --git a/nixos/modules/virtualisation/openstack/glance.nix b/nixos/modules/virtualisation/openstack/glance.nix new file mode 100644 index 00000000000..a7baee985b7 --- /dev/null +++ b/nixos/modules/virtualisation/openstack/glance.nix @@ -0,0 +1,249 @@ +{ config, lib, pkgs, ... }: + +with lib; with import ./common.nix {inherit lib;}; + +let + cfg = config.virtualisation.openstack.glance; + commonConf = '' + [database] + connection = "mysql://${cfg.database.user}:${cfg.database.password.pattern}@${cfg.database.host}/${cfg.database.name}" + notification_driver = noop + + [keystone_authtoken] + auth_url = ${cfg.authUrl} + auth_plugin = password + project_name = service + project_domain_id = default + user_domain_id = default + username = ${cfg.serviceUsername} + password = ${cfg.servicePassword.pattern} + + [glance_store] + default_store = file + filesystem_store_datadir = /var/lib/glance/images/ + ''; + glanceApiConfTpl = pkgs.writeText "glance-api.conf" '' + ${commonConf} + + [paste_deploy] + flavor = keystone + config_file = ${cfg.package}/etc/glance-api-paste.ini + ''; + glanceRegistryConfTpl = pkgs.writeText "glance-registry.conf" '' + ${commonConf} + + [paste_deploy] + config_file = ${cfg.package}/etc/glance-registry-paste.ini + ''; + glanceApiConf = "/var/lib/glance/glance-api.conf"; + glanceRegistryConf = "/var/lib/glance/glance-registry.conf"; + +in { + options.virtualisation.openstack.glance = { + package = mkOption { + type = types.package; + example = literalExample "pkgs.glance"; + description = '' + Glance package to use. + ''; + }; + + enable = mkOption { + default = false; + type = types.bool; + description = '' + This option enables Glance as a single-machine + installation. That is, all of Glance's components are + enabled on this machine. This is useful for evaluating and + experimenting with Glance. Note we are currently not + providing any configurations for a multi-node setup. + ''; + }; + + authUrl = mkOption { + type = types.str; + default = http://localhost:5000; + description = '' + Complete public Identity (Keystone) API endpoint. Note this is + unversionned. + ''; + }; + + serviceUsername = mkOption { + type = types.str; + default = "glance"; + description = '' + The Glance service username. This user is created if bootstrap + is enable, otherwise it has to be manually created before + starting this service. + ''; + }; + + servicePassword = mkSecretOption { + name = "glanceAdminPassword"; + description = '' + The Glance service user's password. + ''; + }; + + database = databaseOption "glance"; + + bootstrap = { + enable = mkOption { + default = false; + type = types.bool; + description = '' + Bootstrap the Glance service by creating the service tenant, + an admin account and a public endpoint. This option provides + a ready-to-use glance service. This is only done at the + first Glance execution by the systemd post start section. + The keystone admin account is used to create required + Keystone resource for the Glance service. + + This option is a helper for setting up + development or testing environments. + ''; + }; + + endpointPublic = mkOption { + type = types.str; + default = "http://localhost:9292"; + description = '' + The public image endpoint. The link + create endpoint provides more informations + about that. + ''; + }; + + keystoneAdminUsername = mkOption { + type = types.str; + default = "admin"; + description = '' + The keystone admin user name used to create the Glance account. + ''; + }; + + keystoneAdminPassword = mkSecretOption { + name = "keystoneAdminPassword"; + description = '' + The keystone admin user's password. + ''; + }; + + keystoneAdminTenant = mkOption { + type = types.str; + default = "admin"; + description = '' + The keystone admin tenant used to create the Glance account. + ''; + }; + keystoneAuthUrl = mkOption { + type = types.str; + default = "http://localhost:5000/v2.0"; + description = '' + The keystone auth url used to create the Glance account. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + # Note: when changing the default, make it conditional on + # ‘system.stateVersion’ to maintain compatibility with existing + # systems! + virtualisation.openstack.glance.package = mkDefault pkgs.glance; + + users.extraUsers = [{ + name = "glance"; + group = "glance"; + uid = config.ids.gids.glance; + + }]; + users.extraGroups = [{ + name = "glance"; + gid = config.ids.gids.glance; + }]; + + systemd.services.glance-registry = { + description = "OpenStack Glance Registry Daemon"; + after = [ "network.target"]; + path = [ pkgs.curl pkgs.pythonPackages.keystoneclient pkgs.gawk ]; + wantedBy = [ "multi-user.target" ]; + preStart = '' + mkdir -m 775 -p /var/lib/glance/{images,scrubber,image_cache} + chown glance:glance /var/lib/glance/{images,scrubber,image_cache} + + # Secret file managment + cp ${glanceRegistryConfTpl} ${glanceRegistryConf}; + chown glance:glance ${glanceRegistryConf}; + chmod 640 ${glanceRegistryConf} + ${replaceSecret cfg.database.password glanceRegistryConf} + ${replaceSecret cfg.servicePassword glanceRegistryConf} + + cp ${glanceApiConfTpl} ${glanceApiConf}; + chown glance:glance ${glanceApiConf}; + chmod 640 ${glanceApiConf} + ${replaceSecret cfg.database.password glanceApiConf} + ${replaceSecret cfg.servicePassword glanceApiConf} + + # Initialise the database + ${cfg.package}/bin/glance-manage --config-file=${glanceApiConf} --config-file=${glanceRegistryConf} db_sync + ''; + postStart = '' + set -eu + export OS_AUTH_URL=${cfg.bootstrap.keystoneAuthUrl} + export OS_USERNAME=${cfg.bootstrap.keystoneAdminUsername} + export OS_PASSWORD=${getSecret cfg.bootstrap.keystoneAdminPassword} + export OS_TENANT_NAME=${cfg.bootstrap.keystoneAdminTenant} + + # Wait until the keystone is available for use + count=0 + while ! keystone user-get ${cfg.bootstrap.keystoneAdminUsername} > /dev/null + do + if [ $count -eq 30 ] + then + echo "Tried 30 times, giving up..." + exit 1 + fi + + echo "Keystone not yet started. Waiting for 1 second..." + count=$((count++)) + sleep 1 + done + + # If the service glance doesn't exist, we consider glance is + # not initialized + if ! keystone service-get glance + then + keystone service-create --type image --name glance + ID=$(keystone service-get glance | awk '/ id / { print $4 }') + keystone endpoint-create --region RegionOne --service $ID --internalurl http://localhost:9292 --adminurl http://localhost:9292 --publicurl ${cfg.bootstrap.endpointPublic} + + keystone user-create --name ${cfg.serviceUsername} --tenant service --pass ${getSecret cfg.servicePassword} + keystone user-role-add --tenant service --user ${cfg.serviceUsername} --role admin + fi + ''; + serviceConfig = { + PermissionsStartOnly = true; # preStart must be run as root + TimeoutStartSec = "600"; # 10min for initial db migrations + User = "glance"; + Group = "glance"; + ExecStart = "${cfg.package}/bin/glance-registry --config-file=${glanceRegistryConf}"; + }; + }; + systemd.services.glance-api = { + description = "OpenStack Glance API Daemon"; + after = [ "glance-registry.service" "network.target"]; + requires = [ "glance-registry.service" "network.target"]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + PermissionsStartOnly = true; # preStart must be run as root + User = "glance"; + Group = "glance"; + ExecStart = "${cfg.package}/bin/glance-api --config-file=${glanceApiConf}"; + }; + }; + }; + +}