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    pub image: String,
333    #[serde(with = "string")]
334    pub port: u16,
335    pub address: String,
336
337    // `--data-dir` only preserves runtime config such as `env.yaml`; it does not
338    // persist topics, subscriptions, or messages across emulator restarts.
339    // https://github.com/risingwavelabs/risingwave/pull/26697#discussion_r3957685142
340    pub persist_data: bool,
341}
342
343#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
344#[serde(rename_all = "kebab-case")]
345#[serde(deny_unknown_fields)]
346pub struct PulsarConfig {
347    #[serde(rename = "use")]
348    phantom_use: Option<String>,
349    pub id: String,
350
351    pub address: String,
352    pub broker_port: u16,
353    pub http_port: u16,
354
355    pub user_managed: bool,
356    pub image: String,
357    pub persist_data: bool,
358}
359
360#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
361#[serde(rename_all = "kebab-case")]
362#[serde(deny_unknown_fields)]
363pub struct RedisConfig {
364    #[serde(rename = "use")]
365    phantom_use: Option<String>,
366    pub id: String,
367
368    pub port: u16,
369    pub address: String,
370
371    pub image: String,
372    pub user_managed: bool,
373    pub persist_data: bool,
374}
375
376#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
377#[serde(rename_all = "kebab-case")]
378#[serde(deny_unknown_fields)]
379pub struct ClickHouseConfig {
380    #[serde(rename = "use")]
381    phantom_use: Option<String>,
382    pub id: String,
383
384    pub address: String,
385    pub http_port: u16,
386    pub native_port: u16,
387
388    pub user: String,
389    pub password: String,
390    pub database: String,
391
392    pub image: String,
393    pub user_managed: bool,
394    pub persist_data: bool,
395}
396
397#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
398#[serde(rename_all = "kebab-case")]
399#[serde(deny_unknown_fields)]
400pub enum Application {
401    Metastore,
402    Connector,
403}
404
405#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
406#[serde(rename_all = "kebab-case")]
407#[serde(deny_unknown_fields)]
408pub struct MySqlConfig {
409    #[serde(rename = "use")]
410    phantom_use: Option<String>,
411    pub id: String,
412
413    pub port: u16,
414    pub address: String,
415
416    pub user: String,
417    pub password: String,
418    pub database: String,
419
420    pub application: Application,
421    pub image: String,
422    pub user_managed: bool,
423    pub persist_data: bool,
424}
425
426#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
427#[serde(rename_all = "kebab-case")]
428#[serde(deny_unknown_fields)]
429pub struct PostgresConfig {
430    #[serde(rename = "use")]
431    phantom_use: Option<String>,
432    pub id: String,
433
434    pub port: u16,
435    pub address: String,
436
437    pub user: String,
438    pub password: String,
439    pub database: String,
440
441    pub application: Application,
442    pub image: String,
443    pub user_managed: bool,
444    pub persist_data: bool,
445
446    // Inject latency into any network calls to the postgres service.
447    pub latency_ms: u32,
448}
449
450#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
451#[serde(rename_all = "kebab-case")]
452#[serde(deny_unknown_fields)]
453pub struct SqlServerConfig {
454    #[serde(rename = "use")]
455    phantom_use: Option<String>,
456    pub id: String,
457
458    pub port: u16,
459    pub address: String,
460
461    pub user: String,
462    pub password: String,
463    pub database: String,
464
465    pub image: String,
466    pub user_managed: bool,
467    pub persist_data: bool,
468}
469
470#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
471#[serde(rename_all = "kebab-case")]
472#[serde(deny_unknown_fields)]
473pub struct MongoDbConfig {
474    #[serde(rename = "use")]
475    phantom_use: Option<String>,
476    pub id: String,
477
478    pub address: String,
479    pub port: u16,
480
481    pub image: String,
482    pub user_managed: bool,
483    pub persist_data: bool,
484}
485
486#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
487#[serde(rename_all = "kebab-case")]
488#[serde(deny_unknown_fields)]
489pub struct NatsConfig {
490    #[serde(rename = "use")]
491    phantom_use: Option<String>,
492    pub id: String,
493
494    pub address: String,
495    pub port: u16,
496    pub monitor_port: u16,
497
498    pub image: String,
499    pub user_managed: bool,
500    pub persist_data: bool,
501}
502
503#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
504#[serde(rename_all = "kebab-case")]
505#[serde(deny_unknown_fields)]
506pub struct MqttConfig {
507    #[serde(rename = "use")]
508    phantom_use: Option<String>,
509    pub id: String,
510
511    pub address: String,
512    pub port: u16,
513
514    pub image: String,
515    pub user_managed: bool,
516    pub persist_data: bool,
517}
518
519#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
520#[serde(rename_all = "kebab-case")]
521#[serde(deny_unknown_fields)]
522pub struct ElasticSearchConfig {
523    #[serde(rename = "use")]
524    phantom_use: Option<String>,
525    pub id: String,
526
527    pub address: String,
528    pub port: u16,
529
530    pub user: String,
531    pub password: String,
532
533    pub image: String,
534    pub user_managed: bool,
535    pub persist_data: bool,
536}
537
538#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
539#[serde(rename_all = "kebab-case")]
540#[serde(deny_unknown_fields)]
541pub struct OpenSearchConfig {
542    #[serde(rename = "use")]
543    phantom_use: Option<String>,
544    pub id: String,
545
546    pub address: String,
547    pub port: u16,
548
549    pub user: String,
550    pub password: String,
551
552    pub image: String,
553    pub user_managed: bool,
554    pub persist_data: bool,
555}
556
557#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
558#[serde(rename_all = "kebab-case")]
559#[serde(deny_unknown_fields)]
560pub struct LakekeeperConfig {
561    #[serde(rename = "use")]
562    phantom_use: Option<String>,
563    pub id: String,
564
565    pub port: u16,
566    pub address: String,
567
568    pub user_managed: bool,
569    pub persist_data: bool,
570
571    pub catalog_backend: String,
572    pub encryption_key: String,
573    pub provide_postgres_backend: Option<Vec<PostgresConfig>>,
574    pub provide_minio: Option<Vec<MinioConfig>>,
575}
576
577#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
578#[serde(rename_all = "kebab-case")]
579#[serde(deny_unknown_fields)]
580pub struct MoatConfig {
581    #[serde(rename = "use")]
582    phantom_use: Option<String>,
583    pub id: String,
584
585    pub address: String,
586    pub port: u16,
587
588    pub provide_minio: Option<Vec<MinioConfig>>,
589}
590
591/// All service configuration
592#[derive(Clone, Debug, PartialEq)]
593pub enum ServiceConfig {
594    ComputeNode(ComputeNodeConfig),
595    MetaNode(MetaNodeConfig),
596    Frontend(FrontendConfig),
597    Compactor(CompactorConfig),
598    Minio(MinioConfig),
599    Sqlite(SqliteConfig),
600    Prometheus(PrometheusConfig),
601    Grafana(GrafanaConfig),
602    Tempo(TempoConfig),
603    Opendal(OpendalConfig),
604    AwsS3(AwsS3Config),
605    Moto(MotoConfig),
606    Kafka(KafkaConfig),
607    SchemaRegistry(SchemaRegistryConfig),
608    Pubsub(PubsubConfig),
609    Pulsar(PulsarConfig),
610    Redis(RedisConfig),
611    ClickHouse(ClickHouseConfig),
612    MySql(MySqlConfig),
613    Postgres(PostgresConfig),
614    SqlServer(SqlServerConfig),
615    MongoDb(MongoDbConfig),
616    ElasticSearch(ElasticSearchConfig),
617    OpenSearch(OpenSearchConfig),
618    Nats(NatsConfig),
619    Mqtt(MqttConfig),
620    Lakekeeper(LakekeeperConfig),
621    Moat(MoatConfig),
622}
623
624#[derive(PartialEq, Eq, Hash, Debug)]
625pub enum TaskGroup {
626    RisingWave,
627    Observability,
628    Kafka,
629    Pubsub,
630    Pulsar,
631    MySql,
632    Postgres,
633    SqlServer,
634    MongoDb,
635    ElasticSearch,
636    OpenSearch,
637    Nats,
638    Mqtt,
639    Redis,
640    ClickHouse,
641    Lakekeeper,
642    Moat,
643}
644
645impl ServiceConfig {
646    pub fn id(&self) -> &str {
647        match self {
648            Self::ComputeNode(c) => &c.id,
649            Self::MetaNode(c) => &c.id,
650            Self::Frontend(c) => &c.id,
651            Self::Compactor(c) => &c.id,
652            Self::Minio(c) => &c.id,
653            Self::Sqlite(c) => &c.id,
654            Self::Prometheus(c) => &c.id,
655            Self::Grafana(c) => &c.id,
656            Self::Tempo(c) => &c.id,
657            Self::AwsS3(c) => &c.id,
658            Self::Moto(c) => &c.id,
659            Self::Kafka(c) => &c.id,
660            Self::Pubsub(c) => &c.id,
661            Self::Pulsar(c) => &c.id,
662            Self::Redis(c) => &c.id,
663            Self::ClickHouse(c) => &c.id,
664            Self::Opendal(c) => &c.id,
665            Self::MySql(c) => &c.id,
666            Self::Postgres(c) => &c.id,
667            Self::SqlServer(c) => &c.id,
668            Self::MongoDb(c) => &c.id,
669            Self::ElasticSearch(c) => &c.id,
670            Self::OpenSearch(c) => &c.id,
671            Self::Nats(c) => &c.id,
672            Self::Mqtt(c) => &c.id,
673            Self::SchemaRegistry(c) => &c.id,
674            Self::Lakekeeper(c) => &c.id,
675            Self::Moat(c) => &c.id,
676        }
677    }
678
679    /// Used to check whether the port is occupied before running the service.
680    pub fn port(&self) -> Option<u16> {
681        match self {
682            Self::ComputeNode(c) => Some(c.port),
683            Self::MetaNode(c) => Some(c.port),
684            Self::Frontend(c) => Some(c.port),
685            Self::Compactor(c) => Some(c.port),
686            Self::Minio(c) => Some(c.port),
687            Self::Sqlite(_) => None,
688            Self::Prometheus(c) => Some(c.port),
689            Self::Grafana(c) => Some(c.port),
690            Self::Tempo(c) => Some(c.port),
691            Self::AwsS3(_) => None,
692            Self::Moto(c) => Some(c.port),
693            Self::Kafka(c) => Some(c.port),
694            Self::Pubsub(c) => Some(c.port),
695            Self::Pulsar(c) => Some(c.http_port),
696            Self::Redis(c) => Some(c.port),
697            Self::ClickHouse(c) => Some(c.http_port),
698            Self::Opendal(_) => None,
699            Self::MySql(c) => Some(c.port),
700            Self::Postgres(c) => Some(c.port),
701            Self::SqlServer(c) => Some(c.port),
702            Self::MongoDb(c) => Some(c.port),
703            Self::ElasticSearch(c) => Some(c.port),
704            Self::OpenSearch(c) => Some(c.port),
705            Self::Nats(c) => Some(c.port),
706            Self::Mqtt(c) => Some(c.port),
707            Self::SchemaRegistry(c) => Some(c.port),
708            Self::Lakekeeper(c) => Some(c.port),
709            Self::Moat(c) => Some(c.port),
710        }
711    }
712
713    pub fn user_managed(&self) -> bool {
714        match self {
715            Self::ComputeNode(c) => c.user_managed,
716            Self::MetaNode(c) => c.user_managed,
717            Self::Frontend(c) => c.user_managed,
718            Self::Compactor(c) => c.user_managed,
719            Self::Minio(_c) => false,
720            Self::Sqlite(_c) => false,
721            Self::Prometheus(_c) => false,
722            Self::Grafana(_c) => false,
723            Self::Tempo(_c) => false,
724            Self::AwsS3(_c) => false,
725            Self::Moto(c) => c.user_managed,
726            Self::Kafka(c) => c.user_managed,
727            Self::Pubsub(c) => c.user_managed,
728            Self::Pulsar(c) => c.user_managed,
729            Self::Redis(c) => c.user_managed,
730            Self::ClickHouse(c) => c.user_managed,
731            Self::Opendal(_c) => false,
732            Self::MySql(c) => c.user_managed,
733            Self::Postgres(c) => c.user_managed,
734            Self::SqlServer(c) => c.user_managed,
735            Self::MongoDb(c) => c.user_managed,
736            Self::ElasticSearch(c) => c.user_managed,
737            Self::OpenSearch(c) => c.user_managed,
738            Self::Nats(c) => c.user_managed,
739            Self::Mqtt(c) => c.user_managed,
740            Self::SchemaRegistry(c) => c.user_managed,
741            Self::Lakekeeper(c) => c.user_managed,
742            Self::Moat(_c) => false,
743        }
744    }
745
746    pub fn task_group(&self) -> TaskGroup {
747        use TaskGroup::*;
748        match self {
749            ServiceConfig::ComputeNode(_)
750            | ServiceConfig::MetaNode(_)
751            | ServiceConfig::Frontend(_)
752            | ServiceConfig::Compactor(_)
753            | ServiceConfig::Minio(_)
754            | ServiceConfig::Sqlite(_) => RisingWave,
755            ServiceConfig::Prometheus(_) | ServiceConfig::Grafana(_) | ServiceConfig::Tempo(_) => {
756                Observability
757            }
758            ServiceConfig::Opendal(_) | ServiceConfig::AwsS3(_) => RisingWave,
759            ServiceConfig::Moto(_) => RisingWave,
760            ServiceConfig::Kafka(_) | ServiceConfig::SchemaRegistry(_) => Kafka,
761            ServiceConfig::Pubsub(_) => Pubsub,
762            ServiceConfig::Pulsar(_) => Pulsar,
763            ServiceConfig::Redis(_) => Redis,
764            ServiceConfig::ClickHouse(_) => ClickHouse,
765            ServiceConfig::MySql(my_sql_config) => {
766                if matches!(my_sql_config.application, Application::Metastore) {
767                    RisingWave
768                } else {
769                    MySql
770                }
771            }
772            ServiceConfig::Postgres(postgres_config) => {
773                if matches!(postgres_config.application, Application::Metastore) {
774                    RisingWave
775                } else {
776                    Postgres
777                }
778            }
779            ServiceConfig::SqlServer(_) => SqlServer,
780            ServiceConfig::MongoDb(_) => MongoDb,
781            ServiceConfig::ElasticSearch(_) => ElasticSearch,
782            ServiceConfig::OpenSearch(_) => OpenSearch,
783            ServiceConfig::Nats(_) => Nats,
784            ServiceConfig::Mqtt(_) => Mqtt,
785            ServiceConfig::Lakekeeper(_) => Lakekeeper,
786            ServiceConfig::Moat(_) => Moat,
787        }
788    }
789}
790
791mod string {
792    use std::fmt::Display;
793    use std::str::FromStr;
794
795    use serde::{Deserialize, Deserializer, Serializer, de};
796
797    pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
798    where
799        T: Display,
800        S: Serializer,
801    {
802        serializer.collect_str(value)
803    }
804
805    pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
806    where
807        T: FromStr,
808        T::Err: Display,
809        D: Deserializer<'de>,
810    {
811        String::deserialize(deserializer)?
812            .parse()
813            .map_err(de::Error::custom)
814    }
815}