Skip to main content

risedev/
service_config.rs

1// Copyright 2022 RisingWave Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use serde::{Deserialize, Serialize};
16
17#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
18#[serde(rename_all = "kebab-case")]
19#[serde(deny_unknown_fields)]
20pub struct ComputeNodeConfig {
21    #[serde(rename = "use")]
22    phantom_use: Option<String>,
23    pub id: String,
24
25    pub address: String,
26    #[serde(with = "string")]
27    pub port: u16,
28    pub listen_address: String,
29    pub exporter_port: u16,
30    pub async_stack_trace: String,
31    pub enable_tiered_cache: bool,
32
33    pub provide_minio: Option<Vec<MinioConfig>>,
34    pub provide_meta_node: Option<Vec<MetaNodeConfig>>,
35    pub provide_compute_node: Option<Vec<ComputeNodeConfig>>,
36    pub provide_opendal: Option<Vec<OpendalConfig>>,
37    pub provide_aws_s3: Option<Vec<AwsS3Config>>,
38    pub provide_moat: Option<Vec<MoatConfig>>,
39    pub provide_tempo: Option<Vec<TempoConfig>>,
40    pub user_managed: bool,
41    pub resource_group: String,
42
43    pub total_memory_bytes: usize,
44    pub parallelism: usize,
45    pub role: String,
46}
47
48#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
49#[serde(rename_all = "kebab-case")]
50#[serde(deny_unknown_fields)]
51pub enum MetaBackend {
52    Memory,
53    Sqlite,
54    Postgres,
55    Mysql,
56    Env,
57}
58
59#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
60#[serde(rename_all = "kebab-case")]
61#[serde(deny_unknown_fields)]
62pub struct MetaNodeConfig {
63    #[serde(rename = "use")]
64    phantom_use: Option<String>,
65    pub id: String,
66
67    pub address: String,
68    #[serde(with = "string")]
69    pub port: u16,
70    pub listen_address: String,
71    pub dashboard_port: u16,
72    pub exporter_port: u16,
73
74    pub user_managed: bool,
75
76    pub meta_backend: MetaBackend,
77    pub provide_sqlite_backend: Option<Vec<SqliteConfig>>,
78    pub provide_postgres_backend: Option<Vec<PostgresConfig>>,
79    pub provide_mysql_backend: Option<Vec<MySqlConfig>>,
80    pub provide_prometheus: Option<Vec<PrometheusConfig>>,
81
82    pub provide_compute_node: Option<Vec<ComputeNodeConfig>>,
83    pub provide_compactor: Option<Vec<CompactorConfig>>,
84
85    pub provide_tempo: Option<Vec<TempoConfig>>,
86
87    pub provide_aws_s3: Option<Vec<AwsS3Config>>,
88    pub provide_minio: Option<Vec<MinioConfig>>,
89    pub provide_opendal: Option<Vec<OpendalConfig>>,
90    pub provide_moat: Option<Vec<MoatConfig>>,
91}
92
93#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
94#[serde(rename_all = "kebab-case")]
95#[serde(deny_unknown_fields)]
96pub struct FrontendConfig {
97    #[serde(rename = "use")]
98    phantom_use: Option<String>,
99    pub id: String,
100
101    pub address: String,
102    #[serde(with = "string")]
103    pub port: u16,
104    pub listen_address: String,
105    pub exporter_port: u16,
106    pub health_check_port: u16,
107
108    pub provide_meta_node: Option<Vec<MetaNodeConfig>>,
109    pub provide_tempo: Option<Vec<TempoConfig>>,
110    pub provide_prometheus: Option<Vec<PrometheusConfig>>,
111
112    pub user_managed: bool,
113}
114
115#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
116#[serde(rename_all = "kebab-case")]
117#[serde(deny_unknown_fields)]
118pub struct CompactorConfig {
119    #[serde(rename = "use")]
120    phantom_use: Option<String>,
121    pub id: String,
122
123    pub address: String,
124    #[serde(with = "string")]
125    pub port: u16,
126    pub listen_address: String,
127    pub exporter_port: u16,
128
129    pub provide_minio: Option<Vec<MinioConfig>>,
130
131    pub provide_meta_node: Option<Vec<MetaNodeConfig>>,
132    pub provide_tempo: Option<Vec<TempoConfig>>,
133
134    pub user_managed: bool,
135    pub compaction_worker_threads_number: Option<usize>,
136
137    pub compactor_mode: String,
138}
139
140#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
141#[serde(rename_all = "kebab-case")]
142#[serde(deny_unknown_fields)]
143pub struct MinioConfig {
144    #[serde(rename = "use")]
145    phantom_use: Option<String>,
146    pub id: String,
147
148    pub address: String,
149    #[serde(with = "string")]
150    pub port: u16,
151    pub listen_address: String,
152
153    pub console_address: String,
154    #[serde(with = "string")]
155    pub console_port: u16,
156
157    pub root_user: String,
158    pub root_password: String,
159    pub hummock_bucket: String,
160
161    pub provide_prometheus: Option<Vec<PrometheusConfig>>,
162
163    // For rate limiting minio in a test environment.
164    pub api_requests_max: usize,
165    pub api_requests_deadline: String,
166}
167
168#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
169#[serde(rename_all = "kebab-case")]
170#[serde(deny_unknown_fields)]
171pub struct SqliteConfig {
172    #[serde(rename = "use")]
173    phantom_use: Option<String>,
174    pub id: String,
175
176    pub file: String,
177}
178
179#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
180#[serde(rename_all = "kebab-case")]
181#[serde(deny_unknown_fields)]
182pub struct PrometheusConfig {
183    #[serde(rename = "use")]
184    phantom_use: Option<String>,
185    pub id: String,
186
187    pub address: String,
188    #[serde(with = "string")]
189    pub port: u16,
190    pub listen_address: String,
191
192    pub remote_write: bool,
193    pub remote_write_region: String,
194    pub remote_write_url: String,
195
196    pub scrape_interval: String,
197
198    pub provide_compute_node: Option<Vec<ComputeNodeConfig>>,
199    pub provide_meta_node: Option<Vec<MetaNodeConfig>>,
200    pub provide_minio: Option<Vec<MinioConfig>>,
201    pub provide_compactor: Option<Vec<CompactorConfig>>,
202    pub provide_frontend: Option<Vec<FrontendConfig>>,
203}
204
205#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
206#[serde(rename_all = "kebab-case")]
207#[serde(deny_unknown_fields)]
208pub struct GrafanaConfig {
209    #[serde(rename = "use")]
210    phantom_use: Option<String>,
211    pub id: String,
212    pub address: String,
213    pub listen_address: String,
214    pub port: u16,
215
216    pub provide_prometheus: Option<Vec<PrometheusConfig>>,
217    pub provide_tempo: Option<Vec<TempoConfig>>,
218}
219
220#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
221#[serde(rename_all = "kebab-case")]
222#[serde(deny_unknown_fields)]
223pub struct TempoConfig {
224    #[serde(rename = "use")]
225    phantom_use: Option<String>,
226    pub id: String,
227
228    pub listen_address: String,
229    pub address: String,
230    pub port: u16,
231    pub otlp_port: u16,
232    pub max_bytes_per_trace: usize,
233}
234
235#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
236#[serde(rename_all = "kebab-case")]
237#[serde(deny_unknown_fields)]
238pub struct AwsS3Config {
239    #[serde(rename = "use")]
240    phantom_use: Option<String>,
241    pub id: String,
242    pub bucket: String,
243}
244
245#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
246#[serde(rename_all = "kebab-case")]
247#[serde(deny_unknown_fields)]
248pub struct MotoConfig {
249    #[serde(rename = "use")]
250    phantom_use: Option<String>,
251    pub id: String,
252
253    pub address: String,
254    #[serde(with = "string")]
255    pub port: u16,
256
257    pub image: String,
258    pub user_managed: bool,
259
260    pub provide_minio: Option<Vec<MinioConfig>>,
261}
262
263#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
264#[serde(rename_all = "kebab-case")]
265#[serde(deny_unknown_fields)]
266pub struct OpendalConfig {
267    #[serde(rename = "use")]
268    phantom_use: Option<String>,
269
270    pub id: String,
271    pub engine: String,
272    pub namenode: String,
273    pub bucket: String,
274}
275
276#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
277#[serde(rename_all = "kebab-case")]
278#[serde(deny_unknown_fields)]
279pub struct KafkaConfig {
280    #[serde(rename = "use")]
281    phantom_use: Option<String>,
282    pub id: String,
283
284    /// Advertise address
285    pub address: String,
286    #[serde(with = "string")]
287    pub port: u16,
288    /// Port for other services in docker. They need to connect to `host.docker.internal`, while the host
289    /// need to connect to `localhost`.
290    pub docker_port: u16,
291
292    #[serde(with = "string")]
293    pub controller_port: u16,
294
295    pub image: String,
296    pub persist_data: bool,
297    pub node_id: u32,
298
299    pub user_managed: bool,
300}
301
302#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
303#[serde(rename_all = "kebab-case")]
304#[serde(deny_unknown_fields)]
305pub struct SchemaRegistryConfig {
306    #[serde(rename = "use")]
307    phantom_use: Option<String>,
308
309    pub id: String,
310
311    pub address: String,
312    #[serde(with = "string")]
313    pub port: u16,
314
315    pub provide_kafka: Option<Vec<KafkaConfig>>,
316
317    pub image: String,
318    /// Redpanda supports schema registry natively. You can configure a `user_managed` schema registry
319    /// to use with redpanda.
320    pub user_managed: bool,
321}
322
323#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
324#[serde(rename_all = "kebab-case")]
325#[serde(deny_unknown_fields)]
326pub struct PubsubConfig {
327    #[serde(rename = "use")]
328    phantom_use: Option<String>,
329    pub id: String,
330    #[serde(default)]
331    pub user_managed: bool,
332    #[serde(with = "string")]
333    pub port: u16,
334    pub address: String,
335
336    pub persist_data: bool,
337}
338
339#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
340#[serde(rename_all = "kebab-case")]
341#[serde(deny_unknown_fields)]
342pub struct PulsarConfig {
343    #[serde(rename = "use")]
344    phantom_use: Option<String>,
345    pub id: String,
346
347    pub address: String,
348    pub broker_port: u16,
349    pub http_port: u16,
350
351    pub user_managed: bool,
352    pub image: String,
353    pub persist_data: bool,
354}
355
356#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
357#[serde(rename_all = "kebab-case")]
358#[serde(deny_unknown_fields)]
359pub struct RedisConfig {
360    #[serde(rename = "use")]
361    phantom_use: Option<String>,
362    pub id: String,
363
364    pub port: u16,
365    pub address: String,
366
367    pub image: String,
368    pub user_managed: bool,
369    pub persist_data: bool,
370}
371
372#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
373#[serde(rename_all = "kebab-case")]
374#[serde(deny_unknown_fields)]
375pub enum Application {
376    Metastore,
377    Connector,
378}
379
380#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
381#[serde(rename_all = "kebab-case")]
382#[serde(deny_unknown_fields)]
383pub struct MySqlConfig {
384    #[serde(rename = "use")]
385    phantom_use: Option<String>,
386    pub id: String,
387
388    pub port: u16,
389    pub address: String,
390
391    pub user: String,
392    pub password: String,
393    pub database: String,
394
395    pub application: Application,
396    pub image: String,
397    pub user_managed: bool,
398    pub persist_data: bool,
399}
400
401#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
402#[serde(rename_all = "kebab-case")]
403#[serde(deny_unknown_fields)]
404pub struct PostgresConfig {
405    #[serde(rename = "use")]
406    phantom_use: Option<String>,
407    pub id: String,
408
409    pub port: u16,
410    pub address: String,
411
412    pub user: String,
413    pub password: String,
414    pub database: String,
415
416    pub application: Application,
417    pub image: String,
418    pub user_managed: bool,
419    pub persist_data: bool,
420
421    // Inject latency into any network calls to the postgres service.
422    pub latency_ms: u32,
423}
424
425#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
426#[serde(rename_all = "kebab-case")]
427#[serde(deny_unknown_fields)]
428pub struct SqlServerConfig {
429    #[serde(rename = "use")]
430    phantom_use: Option<String>,
431    pub id: String,
432
433    pub port: u16,
434    pub address: String,
435
436    pub user: String,
437    pub password: String,
438    pub database: String,
439
440    pub image: String,
441    pub user_managed: bool,
442    pub persist_data: bool,
443}
444
445#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
446#[serde(rename_all = "kebab-case")]
447#[serde(deny_unknown_fields)]
448pub struct MongoDbConfig {
449    #[serde(rename = "use")]
450    phantom_use: Option<String>,
451    pub id: String,
452
453    pub address: String,
454    pub port: u16,
455
456    pub image: String,
457    pub user_managed: bool,
458    pub persist_data: bool,
459}
460
461#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
462#[serde(rename_all = "kebab-case")]
463#[serde(deny_unknown_fields)]
464pub struct NatsConfig {
465    #[serde(rename = "use")]
466    phantom_use: Option<String>,
467    pub id: String,
468
469    pub address: String,
470    pub port: u16,
471    pub monitor_port: u16,
472
473    pub image: String,
474    pub user_managed: bool,
475    pub persist_data: bool,
476}
477
478#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
479#[serde(rename_all = "kebab-case")]
480#[serde(deny_unknown_fields)]
481pub struct MqttConfig {
482    #[serde(rename = "use")]
483    phantom_use: Option<String>,
484    pub id: String,
485
486    pub address: String,
487    pub port: u16,
488
489    pub image: String,
490    pub user_managed: bool,
491    pub persist_data: bool,
492}
493
494#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
495#[serde(rename_all = "kebab-case")]
496#[serde(deny_unknown_fields)]
497pub struct ElasticSearchConfig {
498    #[serde(rename = "use")]
499    phantom_use: Option<String>,
500    pub id: String,
501
502    pub address: String,
503    pub port: u16,
504
505    pub user: String,
506    pub password: String,
507
508    pub image: String,
509    pub user_managed: bool,
510    pub persist_data: bool,
511}
512
513#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
514#[serde(rename_all = "kebab-case")]
515#[serde(deny_unknown_fields)]
516pub struct OpenSearchConfig {
517    #[serde(rename = "use")]
518    phantom_use: Option<String>,
519    pub id: String,
520
521    pub address: String,
522    pub port: u16,
523
524    pub user: String,
525    pub password: String,
526
527    pub image: String,
528    pub user_managed: bool,
529    pub persist_data: bool,
530}
531
532#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
533#[serde(rename_all = "kebab-case")]
534#[serde(deny_unknown_fields)]
535pub struct LakekeeperConfig {
536    #[serde(rename = "use")]
537    phantom_use: Option<String>,
538    pub id: String,
539
540    pub port: u16,
541    pub address: String,
542
543    pub user_managed: bool,
544    pub persist_data: bool,
545
546    pub catalog_backend: String,
547    pub encryption_key: String,
548    pub provide_postgres_backend: Option<Vec<PostgresConfig>>,
549    pub provide_minio: Option<Vec<MinioConfig>>,
550}
551
552#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
553#[serde(rename_all = "kebab-case")]
554#[serde(deny_unknown_fields)]
555pub struct MoatConfig {
556    #[serde(rename = "use")]
557    phantom_use: Option<String>,
558    pub id: String,
559
560    pub address: String,
561    pub port: u16,
562
563    pub provide_minio: Option<Vec<MinioConfig>>,
564}
565
566/// All service configuration
567#[derive(Clone, Debug, PartialEq)]
568pub enum ServiceConfig {
569    ComputeNode(ComputeNodeConfig),
570    MetaNode(MetaNodeConfig),
571    Frontend(FrontendConfig),
572    Compactor(CompactorConfig),
573    Minio(MinioConfig),
574    Sqlite(SqliteConfig),
575    Prometheus(PrometheusConfig),
576    Grafana(GrafanaConfig),
577    Tempo(TempoConfig),
578    Opendal(OpendalConfig),
579    AwsS3(AwsS3Config),
580    Moto(MotoConfig),
581    Kafka(KafkaConfig),
582    SchemaRegistry(SchemaRegistryConfig),
583    Pubsub(PubsubConfig),
584    Pulsar(PulsarConfig),
585    Redis(RedisConfig),
586    MySql(MySqlConfig),
587    Postgres(PostgresConfig),
588    SqlServer(SqlServerConfig),
589    MongoDb(MongoDbConfig),
590    ElasticSearch(ElasticSearchConfig),
591    OpenSearch(OpenSearchConfig),
592    Nats(NatsConfig),
593    Mqtt(MqttConfig),
594    Lakekeeper(LakekeeperConfig),
595    Moat(MoatConfig),
596}
597
598#[derive(PartialEq, Eq, Hash, Debug)]
599pub enum TaskGroup {
600    RisingWave,
601    Observability,
602    Kafka,
603    Pubsub,
604    Pulsar,
605    MySql,
606    Postgres,
607    SqlServer,
608    MongoDb,
609    ElasticSearch,
610    OpenSearch,
611    Nats,
612    Mqtt,
613    Redis,
614    Lakekeeper,
615    Moat,
616}
617
618impl ServiceConfig {
619    pub fn id(&self) -> &str {
620        match self {
621            Self::ComputeNode(c) => &c.id,
622            Self::MetaNode(c) => &c.id,
623            Self::Frontend(c) => &c.id,
624            Self::Compactor(c) => &c.id,
625            Self::Minio(c) => &c.id,
626            Self::Sqlite(c) => &c.id,
627            Self::Prometheus(c) => &c.id,
628            Self::Grafana(c) => &c.id,
629            Self::Tempo(c) => &c.id,
630            Self::AwsS3(c) => &c.id,
631            Self::Moto(c) => &c.id,
632            Self::Kafka(c) => &c.id,
633            Self::Pubsub(c) => &c.id,
634            Self::Pulsar(c) => &c.id,
635            Self::Redis(c) => &c.id,
636            Self::Opendal(c) => &c.id,
637            Self::MySql(c) => &c.id,
638            Self::Postgres(c) => &c.id,
639            Self::SqlServer(c) => &c.id,
640            Self::MongoDb(c) => &c.id,
641            Self::ElasticSearch(c) => &c.id,
642            Self::OpenSearch(c) => &c.id,
643            Self::Nats(c) => &c.id,
644            Self::Mqtt(c) => &c.id,
645            Self::SchemaRegistry(c) => &c.id,
646            Self::Lakekeeper(c) => &c.id,
647            Self::Moat(c) => &c.id,
648        }
649    }
650
651    /// Used to check whether the port is occupied before running the service.
652    pub fn port(&self) -> Option<u16> {
653        match self {
654            Self::ComputeNode(c) => Some(c.port),
655            Self::MetaNode(c) => Some(c.port),
656            Self::Frontend(c) => Some(c.port),
657            Self::Compactor(c) => Some(c.port),
658            Self::Minio(c) => Some(c.port),
659            Self::Sqlite(_) => None,
660            Self::Prometheus(c) => Some(c.port),
661            Self::Grafana(c) => Some(c.port),
662            Self::Tempo(c) => Some(c.port),
663            Self::AwsS3(_) => None,
664            Self::Moto(c) => Some(c.port),
665            Self::Kafka(c) => Some(c.port),
666            Self::Pubsub(c) => Some(c.port),
667            Self::Pulsar(c) => Some(c.http_port),
668            Self::Redis(c) => Some(c.port),
669            Self::Opendal(_) => None,
670            Self::MySql(c) => Some(c.port),
671            Self::Postgres(c) => Some(c.port),
672            Self::SqlServer(c) => Some(c.port),
673            Self::MongoDb(c) => Some(c.port),
674            Self::ElasticSearch(c) => Some(c.port),
675            Self::OpenSearch(c) => Some(c.port),
676            Self::Nats(c) => Some(c.port),
677            Self::Mqtt(c) => Some(c.port),
678            Self::SchemaRegistry(c) => Some(c.port),
679            Self::Lakekeeper(c) => Some(c.port),
680            Self::Moat(c) => Some(c.port),
681        }
682    }
683
684    pub fn user_managed(&self) -> bool {
685        match self {
686            Self::ComputeNode(c) => c.user_managed,
687            Self::MetaNode(c) => c.user_managed,
688            Self::Frontend(c) => c.user_managed,
689            Self::Compactor(c) => c.user_managed,
690            Self::Minio(_c) => false,
691            Self::Sqlite(_c) => false,
692            Self::Prometheus(_c) => false,
693            Self::Grafana(_c) => false,
694            Self::Tempo(_c) => false,
695            Self::AwsS3(_c) => false,
696            Self::Moto(c) => c.user_managed,
697            Self::Kafka(c) => c.user_managed,
698            Self::Pubsub(c) => c.user_managed,
699            Self::Pulsar(c) => c.user_managed,
700            Self::Redis(c) => c.user_managed,
701            Self::Opendal(_c) => false,
702            Self::MySql(c) => c.user_managed,
703            Self::Postgres(c) => c.user_managed,
704            Self::SqlServer(c) => c.user_managed,
705            Self::MongoDb(c) => c.user_managed,
706            Self::ElasticSearch(c) => c.user_managed,
707            Self::OpenSearch(c) => c.user_managed,
708            Self::Nats(c) => c.user_managed,
709            Self::Mqtt(c) => c.user_managed,
710            Self::SchemaRegistry(c) => c.user_managed,
711            Self::Lakekeeper(c) => c.user_managed,
712            Self::Moat(_c) => false,
713        }
714    }
715
716    pub fn task_group(&self) -> TaskGroup {
717        use TaskGroup::*;
718        match self {
719            ServiceConfig::ComputeNode(_)
720            | ServiceConfig::MetaNode(_)
721            | ServiceConfig::Frontend(_)
722            | ServiceConfig::Compactor(_)
723            | ServiceConfig::Minio(_)
724            | ServiceConfig::Sqlite(_) => RisingWave,
725            ServiceConfig::Prometheus(_) | ServiceConfig::Grafana(_) | ServiceConfig::Tempo(_) => {
726                Observability
727            }
728            ServiceConfig::Opendal(_) | ServiceConfig::AwsS3(_) => RisingWave,
729            ServiceConfig::Moto(_) => RisingWave,
730            ServiceConfig::Kafka(_) | ServiceConfig::SchemaRegistry(_) => Kafka,
731            ServiceConfig::Pubsub(_) => Pubsub,
732            ServiceConfig::Pulsar(_) => Pulsar,
733            ServiceConfig::Redis(_) => Redis,
734            ServiceConfig::MySql(my_sql_config) => {
735                if matches!(my_sql_config.application, Application::Metastore) {
736                    RisingWave
737                } else {
738                    MySql
739                }
740            }
741            ServiceConfig::Postgres(postgres_config) => {
742                if matches!(postgres_config.application, Application::Metastore) {
743                    RisingWave
744                } else {
745                    Postgres
746                }
747            }
748            ServiceConfig::SqlServer(_) => SqlServer,
749            ServiceConfig::MongoDb(_) => MongoDb,
750            ServiceConfig::ElasticSearch(_) => ElasticSearch,
751            ServiceConfig::OpenSearch(_) => OpenSearch,
752            ServiceConfig::Nats(_) => Nats,
753            ServiceConfig::Mqtt(_) => Mqtt,
754            ServiceConfig::Lakekeeper(_) => Lakekeeper,
755            ServiceConfig::Moat(_) => Moat,
756        }
757    }
758}
759
760mod string {
761    use std::fmt::Display;
762    use std::str::FromStr;
763
764    use serde::{Deserialize, Deserializer, Serializer, de};
765
766    pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
767    where
768        T: Display,
769        S: Serializer,
770    {
771        serializer.collect_str(value)
772    }
773
774    pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
775    where
776        T: FromStr,
777        T::Err: Display,
778        D: Deserializer<'de>,
779    {
780        String::deserialize(deserializer)?
781            .parse()
782            .map_err(de::Error::custom)
783    }
784}