2024-02-07 19:33:06 +03:00
# Based on: https://github.com/cachix/devenv/blob/main/src/modules/services/clickhouse.nix
{ pkgs , lib , name , config , . . . }:
let
inherit ( lib ) types ;
2024-02-19 08:38:14 +03:00
yamlFormat = pkgs . formats . yaml { } ;
2024-02-07 19:33:06 +03:00
in
{
options = {
enable = lib . mkEnableOption name ;
package = lib . mkOption {
type = types . package ;
description = " W h i c h p a c k a g e o f c l i c k h o u s e t o u s e " ;
default = pkgs . clickhouse ;
defaultText = lib . literalExpression " p k g s . c l i c k h o u s e " ;
} ;
port = lib . mkOption {
type = types . int ;
description = " W h i c h p o r t t o r u n c l i c k h o u s e o n . T h i s p o r t i s f o r ` c l i c k h o u s e - c l i e n t ` p r o g r a m " ;
default = 9000 ;
} ;
dataDir = lib . mkOption {
type = types . str ;
default = " . / d a t a / ${ name } " ;
description = " T h e c l i c k h o u s e d a t a d i r e c t o r y " ;
} ;
2024-02-22 20:02:52 +03:00
defaultExtraConfig = lib . mkOption {
type = yamlFormat . type ;
internal = true ;
readOnly = true ;
default = {
logger . level = " w a r n i n g " ;
logger . console = 1 ;
default_profile = " d e f a u l t " ;
default_database = " d e f a u l t " ;
tcp_port = toString config . port ;
path = " ${ config . dataDir } / c l i c k h o u s e " ;
tmp_path = " ${ config . dataDir } / c l i c k h o u s e / t m p " ;
user_files_path = " ${ config . dataDir } / c l i c k h o u s e / u s e r _ f i l e s " ;
format_schema_path = " ${ config . dataDir } / c l i c k h o u s e / f o r m a t _ s c h e m a s " ;
user_directories = {
users_xml = {
path = " ${ config . package } / e t c / c l i c k h o u s e - s e r v e r / u s e r s . x m l " ;
} ;
} ;
} ;
} ;
2024-02-07 19:33:06 +03:00
extraConfig = lib . mkOption {
2024-02-19 08:38:14 +03:00
type = yamlFormat . type ;
2024-02-07 19:33:06 +03:00
description = " A d d i t i o n a l c o n f i g u r a t i o n t o b e a p p e n d e d t o ` c l i c k h o u s e - c o n f i g . y a m l ` . " ;
2024-02-19 08:38:14 +03:00
default = { } ;
2024-02-07 19:33:06 +03:00
} ;
initialDatabases = lib . mkOption {
type = types . listOf ( types . submodule {
options = {
name = lib . mkOption {
type = types . str ;
description = ''
The name of the database to create .
'' ;
} ;
schemas = lib . mkOption {
type = types . nullOr ( types . listOf types . path ) ;
default = null ;
description = ''
The initial list of schemas for the database ; if null ( the default ) ,
an empty database is created .
'' ;
} ;
} ;
} ) ;
default = [ ] ;
description = ''
List of database names and their initial schemas that should be used to create databases on the first startup
of Postgres . The schema attribute is optional : If not specified , an empty database is created .
'' ;
example = lib . literalExpression ''
[
{
name = " f o o d a t a b a s e " ;
schemas = [ ./fooschemas ./bar.sql ] ;
}
{ name = " b a r d a t a b a s e " ; }
]
'' ;
} ;
outputs . settings = lib . mkOption {
type = types . deferredModule ;
internal = true ;
readOnly = true ;
default = {
processes =
let
2024-02-19 08:38:14 +03:00
clickhouseConfig = yamlFormat . generate " c l i c k h o u s e - c o n f i g . y a m l " (
2024-02-22 20:02:52 +03:00
lib . recursiveUpdate config . defaultExtraConfig config . extraConfig
2024-02-19 08:38:14 +03:00
) ;
2024-02-07 19:33:06 +03:00
in
{
# DB initialization
" ${ name } - i n i t " =
let
# https://github.com/ClickHouse/ClickHouse/issues/4491
setupInitialSchema = schema : '' < ${ schema } t r - s ' \ r \ n ' ' ' | c l i c k h o u s e - c l i e n t - m n - - p o r t ${ builtins . toString config . port } ; '' ;
setupInitialDatabases =
lib . concatMapStrings
( database : ''
echo " C r e a t i n g d a t a b a s e : ${ database . name } "
clickhouse-client - - port $ { builtins . toString config . port } - - query " C R E A T E D A T A B A S E i F N O T E X I S T S ${ database . name } "
echo " D a t a b a s e s u c c e s s f u l l y c r e a t e d : ${ database . name } "
$ { lib . optionalString ( database . schemas != null )
( lib . concatMapStrings ( schema : setupInitialSchema schema ) database . schemas ) }
'' )
config . initialDatabases ;
setupScript = pkgs . writeShellApplication {
name = " s e t u p - c l i c k h o u s e " ;
runtimeInputs = with pkgs ; [ config . package coreutils gnugrep gawk ] ;
# TODO: Find a better way to start clickhouse-server than waiting for 5 seconds: https://github.com/juspay/services-flake/pull/91#discussion_r1481710799
text = ''
if test - d $ { config . dataDir }
then echo " C l i c k h o u s e d a t a b a s e d i r e c t o r y ${ config . dataDir } a p p e a r s t o c o n t a i n a d a t a b a s e ; S k i p p i n g i n i t i a l i z a t i o n "
else
echo " C l i c k h o u s e i s s e t t i n g u p t h e i n i t i a l d a t a b a s e . "
set - m
clickhouse-server - - config-file = $ { clickhouseConfig } &
sleep 5 s
echo " C l i c k h o u s e s e r v e r s t a r t e d . "
$ { setupInitialDatabases }
echo " C l i c k h o u s e d b s e t t i n g i s d o n e . "
kill % 1
echo " C l i c k h o u s e s e r v e r s t o p p e d . "
fi
'' ;
} ;
in
{
command = setupScript ;
namespace = name ;
} ;
# DB process
" ${ name } " =
let
startScript = pkgs . writeShellApplication {
name = " s t a r t - c l i c k h o u s e " ;
runtimeInputs = [ config . package ] ;
text = ''
clickhouse-server - - config-file = $ { clickhouseConfig }
'' ;
} ;
in
{
2024-03-18 23:17:25 +03:00
command = startScript ;
2024-02-07 19:33:06 +03:00
readiness_probe = {
2024-02-27 17:05:08 +03:00
# FIXME: revert back to clickhouse-client readiness_probe once CI is moved out of github public runners
# See: https://github.com/juspay/services-flake/issues/100
# exec.command = ''${config.package}/bin/clickhouse-client --query "SELECT 1" --port ${builtins.toString config.port}'';
http_get = {
host = " l o c a l h o s t " ;
port = if ( lib . hasAttr " h t t p _ p o r t " config . extraConfig ) then config . extraConfig . http_port else 8123 ;
} ;
2024-02-07 19:33:06 +03:00
initial_delay_seconds = 2 ;
period_seconds = 10 ;
timeout_seconds = 4 ;
success_threshold = 1 ;
failure_threshold = 5 ;
} ;
namespace = name ;
depends_on . " ${ name } - i n i t " . condition = " p r o c e s s _ c o m p l e t e d _ s u c c e s s f u l l y " ;
# https://github.com/F1bonacc1/process-compose#-auto-restart-if-not-healthy
availability . restart = " o n _ f a i l u r e " ;
} ;
} ;
} ;
} ;
} ;
}