From 1394f69df9db35ed6dc81e218808b2a06176ac9f Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Wed, 6 Nov 2024 09:45:17 -0800 Subject: [PATCH] Make main() code consistent (#8034) # Description This change updates each entry point of our microservices to the following in a more consistent way. - Use cobra for argument parsing and help. - Accept the configuration file using `--config-file` as a commandline option. - Use a consistent pattern for choosing the ports used for various purposes. The port changes only affect local development. In Kuberentes each pod can choose its own listening port without conflict. ## Type of change - This pull request is a minor refactor, code cleanup, test improvement, or other maintenance task and doesn't change the functionality of Radius (issue link optional). ## Contributor checklist Please verify that the PR meets the following requirements, where applicable: - [ ] An overview of proposed schema changes is included in a linked GitHub issue. - [ ] A design document PR is created in the [design-notes repository](https://github.com/radius-project/design-notes/), if new APIs are being introduced. - [ ] If applicable, design document has been reviewed and approved by Radius maintainers/approvers. - [ ] A PR for the [samples repository](https://github.com/radius-project/samples) is created, if existing samples are affected by the changes in this PR. - [ ] A PR for the [documentation repository](https://github.com/radius-project/docs) is created, if the changes in this PR affect the documentation or any user facing updates are made. - [ ] A PR for the [recipes repository](https://github.com/radius-project/recipes) is created, if existing recipes are affected by the changes in this PR. Signed-off-by: Ryan Nowak --- .vscode/launch.json | 271 +++++++++--------- cmd/applications-rp/cmd/root.go | 138 +++++++++ cmd/applications-rp/main.go | 126 +------- cmd/controller/cmd/root.go | 80 ++++++ cmd/controller/main.go | 56 +--- cmd/ucpd/cmd/root.go | 11 +- ...{ucp-self-hosted-dev.yaml => ucp-dev.yaml} | 0 deploy/Chart/templates/ucp/deployment.yaml | 4 +- docs/ucp/developer_guide.md | 3 +- pkg/ucp/server/server.go | 6 +- 10 files changed, 373 insertions(+), 322 deletions(-) create mode 100644 cmd/applications-rp/cmd/root.go create mode 100644 cmd/controller/cmd/root.go rename cmd/ucpd/{ucp-self-hosted-dev.yaml => ucp-dev.yaml} (100%) diff --git a/.vscode/launch.json b/.vscode/launch.json index cc9a853f27..d98ac8286c 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,134 +1,139 @@ { - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "Debug rad CLI", - "type": "go", - "request": "launch", - "mode": "auto", - "preLaunchTask": "Build Radius (all)", - "program": "${workspaceFolder}/cmd/rad/main.go", - "cwd": "${workspaceFolder}", - "args": [], - }, - { - "name": "Debug rad CLI (prompt for args)", - "type": "go", - "request": "launch", - "mode": "debug", - "preLaunchTask": "Build Radius (all)", - "program": "${workspaceFolder}/cmd/rad", - "args": "${input:cliArgs}", - "console": "integratedTerminal", - }, - { - "name": "Launch Applications RP", - "type": "go", - "request": "launch", - "mode": "auto", - "preLaunchTask": "Build Radius (all)", - "program": "${workspaceFolder}/cmd/applications-rp/main.go", - "args": [ - "--config-file", - "${workspaceFolder}/cmd/applications-rp/radius-self-hosted.yaml", - ], - "env": { - "RADIUS_ENV": "self-hosted" - } - },{ - "name": "Launch Dynamic RP", - "type": "go", - "request": "launch", - "mode": "auto", - "preLaunchTask": "Build Radius (all)", - "program": "${workspaceFolder}/cmd/dynamic-rp/main.go", - }, - { - "name": "Launch UCP", - "type": "go", - "request": "launch", - "mode": "auto", - "preLaunchTask": "Build Radius (all)", - "program": "${workspaceFolder}/cmd/ucpd/main.go", - "cwd": "${workspaceFolder}", - "env": { - "BASE_PATH": "/apis/api.ucp.dev/v1alpha3", - "PORT": "9000", - "UCP_CONFIG": "${workspaceFolder}/cmd/ucpd/ucp-self-hosted-dev.yaml" - } - }, - { - "name": "Launch Controller", - "type": "go", - "request": "launch", - "mode": "auto", - "preLaunchTask": "Build Radius (all)", - "program": "${workspaceFolder}/cmd/controller/main.go", - "cwd": "${workspaceFolder}", - "args": [ - "--config-file", - "${workspaceFolder}/cmd/controller/controller-self-hosted.yaml", - "--cert-dir", - "" - ], - "env": { - "RADIUS_ENV": "self-hosted" - } - }, - { - "name": "Launch Deployment Engine", - "type": "coreclr", - "request": "launch", - "preLaunchTask": "Build Deployment Engine", - "program": "${workspaceFolder}/../deployment-engine/src/DeploymentEngine/bin/Debug/net6.0/arm-de.dll", - "args": [], - "cwd": "${workspaceFolder}/../deployment-engine/src/DeploymentEngine", - "stopAtEntry": false, - "env": { - "ASPNETCORE_URLS": "http://localhost:5017", - "ASPNETCORE_ENVIRONMENT": "Development", - "KUBERNETESBICEPEXTENSIBILITYURL": "http://localhost:5017/api", - "RADIUSBACKENDURI": "http://localhost:9000", - }, - }, - { - "name": "Debug Bicep generator integration tests", - "type": "node", - "request": "launch", - "runtimeArgs": [ - "--inspect-brk", - "${workspaceRoot}/hack/bicep-types-radius/src/autorest.bicep/node_modules/.bin/jest", - "--runInBand", - "--no-cache" - ], - "cwd": "${workspaceFolder}/hack/bicep-types-radius/src/autorest.bicep/src", - "console": "integratedTerminal", - "internalConsoleOptions": "neverOpen", - "sourceMaps": true - }, - ], - "compounds": [ - { - "name": "Launch Control Plane (all)", - "configurations": [ - "Launch UCP", - "Launch Dynamic RP", - "Launch Applications RP", - "Launch Controller", - "Launch Deployment Engine", - ], - "stopAll": true - } - ], - "inputs": [ - { - "id": "cliArgs", - "type": "promptString", - "description": "Args for launching Radius cli. Use --cwd to set the working directory.", - "default": "init --full" - } - ] -} \ No newline at end of file + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Debug rad CLI", + "type": "go", + "request": "launch", + "mode": "auto", + "preLaunchTask": "Build Radius (all)", + "program": "${workspaceFolder}/cmd/rad/main.go", + "cwd": "${workspaceFolder}", + "args": [] + }, + { + "name": "Debug rad CLI (prompt for args)", + "type": "go", + "request": "launch", + "mode": "debug", + "preLaunchTask": "Build Radius (all)", + "program": "${workspaceFolder}/cmd/rad", + "args": "${input:cliArgs}", + "console": "integratedTerminal" + }, + { + "name": "Launch Applications RP", + "type": "go", + "request": "launch", + "mode": "auto", + "preLaunchTask": "Build Radius (all)", + "program": "${workspaceFolder}/cmd/applications-rp/main.go", + "args": [ + "--config-file", + "${workspaceFolder}/cmd/applications-rp/radius-self-hosted.yaml" + ], + "env": { + "RADIUS_ENV": "self-hosted" + } + }, + { + "name": "Launch Dynamic RP", + "type": "go", + "request": "launch", + "mode": "auto", + "preLaunchTask": "Build Radius (all)", + "program": "${workspaceFolder}/cmd/dynamic-rp/main.go", + }, + { + "name": "Launch UCP", + "type": "go", + "request": "launch", + "mode": "auto", + "preLaunchTask": "Build Radius (all)", + "program": "${workspaceFolder}/cmd/ucpd/main.go", + "cwd": "${workspaceFolder}", + "args": [ + "--config-file", + "${workspaceFolder}/cmd/ucpd/ucp-dev.yaml" + ], + "env": { + "BASE_PATH": "/apis/api.ucp.dev/v1alpha3", + "PORT": "9000", + "UCP_CONFIG": "${workspaceFolder}/cmd/ucpd/ucp-self-hosted-dev.yaml" + } + }, + { + "name": "Launch Controller", + "type": "go", + "request": "launch", + "mode": "auto", + "preLaunchTask": "Build Radius (all)", + "program": "${workspaceFolder}/cmd/controller/main.go", + "cwd": "${workspaceFolder}", + "args": [ + "--config-file", + "${workspaceFolder}/cmd/controller/controller-self-hosted.yaml", + "--cert-dir", + "" + ], + "env": { + "RADIUS_ENV": "self-hosted" + } + }, + { + "name": "Launch Deployment Engine", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "Build Deployment Engine", + "program": "${workspaceFolder}/../deployment-engine/src/DeploymentEngine/bin/Debug/net6.0/arm-de.dll", + "args": [], + "cwd": "${workspaceFolder}/../deployment-engine/src/DeploymentEngine", + "stopAtEntry": false, + "env": { + "ASPNETCORE_URLS": "http://localhost:5017", + "ASPNETCORE_ENVIRONMENT": "Development", + "KUBERNETESBICEPEXTENSIBILITYURL": "http://localhost:5017/api", + "RADIUSBACKENDURI": "http://localhost:9000" + } + }, + { + "name": "Debug Bicep generator integration tests", + "type": "node", + "request": "launch", + "runtimeArgs": [ + "--inspect-brk", + "${workspaceRoot}/hack/bicep-types-radius/src/autorest.bicep/node_modules/.bin/jest", + "--runInBand", + "--no-cache" + ], + "cwd": "${workspaceFolder}/hack/bicep-types-radius/src/autorest.bicep/src", + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen", + "sourceMaps": true + } + ], + "compounds": [ + { + "name": "Launch Control Plane (all)", + "configurations": [ + "Launch UCP", + "Launch Applications RP", + "Launch Dynamic RP", + "Launch Controller", + "Launch Deployment Engine" + ], + "stopAll": true + } + ], + "inputs": [ + { + "id": "cliArgs", + "type": "promptString", + "description": "Args for launching Radius cli. Use --cwd to set the working directory.", + "default": "init --full" + } + ] +} diff --git a/cmd/applications-rp/cmd/root.go b/cmd/applications-rp/cmd/root.go new file mode 100644 index 0000000000..88650ee966 --- /dev/null +++ b/cmd/applications-rp/cmd/root.go @@ -0,0 +1,138 @@ +/* +Copyright 2023 The Radius Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cmd + +import ( + "context" + "fmt" + + "github.com/go-logr/logr" + "github.com/spf13/cobra" + etcdclient "go.etcd.io/etcd/client/v3" + runtimelog "sigs.k8s.io/controller-runtime/pkg/log" + + "github.com/radius-project/radius/pkg/armrpc/builder" + "github.com/radius-project/radius/pkg/armrpc/hostoptions" + metricsservice "github.com/radius-project/radius/pkg/metrics/service" + profilerservice "github.com/radius-project/radius/pkg/profiler/service" + "github.com/radius-project/radius/pkg/recipes/controllerconfig" + "github.com/radius-project/radius/pkg/server" + "github.com/radius-project/radius/pkg/trace" + + "github.com/radius-project/radius/pkg/ucp/data" + "github.com/radius-project/radius/pkg/ucp/dataprovider" + "github.com/radius-project/radius/pkg/ucp/hosting" + "github.com/radius-project/radius/pkg/ucp/ucplog" + + corerp_setup "github.com/radius-project/radius/pkg/corerp/setup" + daprrp_setup "github.com/radius-project/radius/pkg/daprrp/setup" + dsrp_setup "github.com/radius-project/radius/pkg/datastoresrp/setup" + msgrp_setup "github.com/radius-project/radius/pkg/messagingrp/setup" +) + +const serviceName = "radius" + +var rootCmd = &cobra.Command{ + Use: "applications-rp", + Short: "Applications.* Resource Provider Server", + Long: `Server process for the Applications.* Resource Provider (applications-rp).`, + RunE: func(cmd *cobra.Command, args []string) error { + configFilePath := cmd.Flag("config-file").Value.String() + options, err := hostoptions.NewHostOptionsFromEnvironment(configFilePath) + if err != nil { + return err + } + + hostingSvc := []hosting.Service{} + + metricOptions := metricsservice.NewHostOptionsFromEnvironment(*options.Config) + metricOptions.Config.ServiceName = serviceName + if metricOptions.Config.Prometheus.Enabled { + hostingSvc = append(hostingSvc, metricsservice.NewService(metricOptions)) + } + + profilerOptions := profilerservice.NewHostOptionsFromEnvironment(*options.Config) + if profilerOptions.Config.Enabled { + hostingSvc = append(hostingSvc, profilerservice.NewService(profilerOptions)) + } + + logger, flush, err := ucplog.NewLogger(serviceName, &options.Config.Logging) + if err != nil { + return err + } + defer flush() + + // Must set the logger before using controller-runtime. + runtimelog.SetLogger(logger) + + if options.Config.StorageProvider.Provider == dataprovider.TypeETCD && + options.Config.StorageProvider.ETCD.InMemory { + // For in-memory etcd we need to register another service to manage its lifecycle. + // + // The client will be initialized asynchronously. + logger.Info("Enabled in-memory etcd") + client := hosting.NewAsyncValue[etcdclient.Client]() + options.Config.StorageProvider.ETCD.Client = client + options.Config.SecretProvider.ETCD.Client = client + + hostingSvc = append(hostingSvc, data.NewEmbeddedETCDService(data.EmbeddedETCDServiceOptions{ClientConfigSink: client})) + } + + builders, err := builders(options) + if err != nil { + return err + } + + hostingSvc = append( + hostingSvc, + server.NewAPIService(options, builders), + server.NewAsyncWorker(options, builders), + ) + + tracerOpts := options.Config.TracerProvider + tracerOpts.ServiceName = serviceName + hostingSvc = append(hostingSvc, &trace.Service{Options: tracerOpts}) + + host := &hosting.Host{ + Services: hostingSvc, + } + + ctx := logr.NewContext(context.Background(), logger) + return hosting.RunWithInterrupts(ctx, host) + }, +} + +func Execute() { + // Let users override the configuration via `--config-file`. + rootCmd.Flags().String("config-file", fmt.Sprintf("radius-%s.yaml", hostoptions.Environment()), "The service configuration file.") + cobra.CheckErr(rootCmd.ExecuteContext(context.Background())) +} + +func builders(options hostoptions.HostOptions) ([]builder.Builder, error) { + config, err := controllerconfig.New(options) + if err != nil { + return nil, err + } + + return []builder.Builder{ + corerp_setup.SetupNamespace(config).GenerateBuilder(), + daprrp_setup.SetupNamespace(config).GenerateBuilder(), + msgrp_setup.SetupNamespace(config).GenerateBuilder(), + dsrp_setup.SetupNamespace(config).GenerateBuilder(), + // Add resource provider builders... + }, nil +} diff --git a/cmd/applications-rp/main.go b/cmd/applications-rp/main.go index fd7a1231db..d30d960bab 100644 --- a/cmd/applications-rp/main.go +++ b/cmd/applications-rp/main.go @@ -16,130 +16,8 @@ limitations under the License. package main -import ( - "context" - "fmt" - "log" - "os" - - "github.com/go-logr/logr" - "github.com/spf13/pflag" - etcdclient "go.etcd.io/etcd/client/v3" - runtimelog "sigs.k8s.io/controller-runtime/pkg/log" - - "github.com/radius-project/radius/pkg/armrpc/builder" - "github.com/radius-project/radius/pkg/armrpc/hostoptions" - metricsservice "github.com/radius-project/radius/pkg/metrics/service" - profilerservice "github.com/radius-project/radius/pkg/profiler/service" - "github.com/radius-project/radius/pkg/recipes/controllerconfig" - "github.com/radius-project/radius/pkg/server" - "github.com/radius-project/radius/pkg/trace" - - "github.com/radius-project/radius/pkg/ucp/data" - "github.com/radius-project/radius/pkg/ucp/dataprovider" - "github.com/radius-project/radius/pkg/ucp/hosting" - "github.com/radius-project/radius/pkg/ucp/ucplog" - - corerp_setup "github.com/radius-project/radius/pkg/corerp/setup" - daprrp_setup "github.com/radius-project/radius/pkg/daprrp/setup" - dsrp_setup "github.com/radius-project/radius/pkg/datastoresrp/setup" - msgrp_setup "github.com/radius-project/radius/pkg/messagingrp/setup" -) - -const serviceName = "radius" +import "github.com/radius-project/radius/cmd/applications-rp/cmd" func main() { - var configFile string - defaultConfig := fmt.Sprintf("radius-%s.yaml", hostoptions.Environment()) - pflag.StringVar(&configFile, "config-file", defaultConfig, "The service configuration file.") - if configFile == "" { - log.Fatal("config-file is empty.") //nolint:forbidigo // this is OK inside the main function. - } - pflag.Parse() - - options, err := hostoptions.NewHostOptionsFromEnvironment(configFile) - if err != nil { - log.Fatal(err) //nolint:forbidigo // this is OK inside the main function. - } - - hostingSvc := []hosting.Service{} - - metricOptions := metricsservice.NewHostOptionsFromEnvironment(*options.Config) - metricOptions.Config.ServiceName = serviceName - if metricOptions.Config.Prometheus.Enabled { - hostingSvc = append(hostingSvc, metricsservice.NewService(metricOptions)) - } - - profilerOptions := profilerservice.NewHostOptionsFromEnvironment(*options.Config) - if profilerOptions.Config.Enabled { - hostingSvc = append(hostingSvc, profilerservice.NewService(profilerOptions)) - } - - logger, flush, err := ucplog.NewLogger(serviceName, &options.Config.Logging) - if err != nil { - log.Fatal(err) //nolint:forbidigo // this is OK inside the main function. - } - defer flush() - - // Must set the logger before using controller-runtime. - runtimelog.SetLogger(logger) - - if options.Config.StorageProvider.Provider == dataprovider.TypeETCD && - options.Config.StorageProvider.ETCD.InMemory { - // For in-memory etcd we need to register another service to manage its lifecycle. - // - // The client will be initialized asynchronously. - logger.Info("Enabled in-memory etcd") - client := hosting.NewAsyncValue[etcdclient.Client]() - options.Config.StorageProvider.ETCD.Client = client - options.Config.SecretProvider.ETCD.Client = client - - hostingSvc = append(hostingSvc, data.NewEmbeddedETCDService(data.EmbeddedETCDServiceOptions{ClientConfigSink: client})) - } - - builders, err := builders(options) - if err != nil { - log.Fatal(err) //nolint:forbidigo // this is OK inside the main function. - } - - hostingSvc = append( - hostingSvc, - server.NewAPIService(options, builders), - server.NewAsyncWorker(options, builders), - ) - - tracerOpts := options.Config.TracerProvider - tracerOpts.ServiceName = serviceName - hostingSvc = append(hostingSvc, &trace.Service{Options: tracerOpts}) - - host := &hosting.Host{ - Services: hostingSvc, - } - - ctx := logr.NewContext(context.Background(), logger) - - err = hosting.RunWithInterrupts(ctx, host) - - // Finished shutting down. An error returned here is a failure to terminate - // gracefully, so just crash if that happens. - if err == nil { - os.Exit(0) //nolint:forbidigo // this is OK inside the main function. - } else { - panic(err) - } -} - -func builders(options hostoptions.HostOptions) ([]builder.Builder, error) { - config, err := controllerconfig.New(options) - if err != nil { - return nil, err - } - - return []builder.Builder{ - corerp_setup.SetupNamespace(config).GenerateBuilder(), - daprrp_setup.SetupNamespace(config).GenerateBuilder(), - msgrp_setup.SetupNamespace(config).GenerateBuilder(), - dsrp_setup.SetupNamespace(config).GenerateBuilder(), - // Add resource provider builders... - }, nil + cmd.Execute() } diff --git a/cmd/controller/cmd/root.go b/cmd/controller/cmd/root.go new file mode 100644 index 0000000000..88137025c4 --- /dev/null +++ b/cmd/controller/cmd/root.go @@ -0,0 +1,80 @@ +/* +Copyright 2023 The Radius Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cmd + +import ( + "context" + "fmt" + + // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) + // to ensure that exec-entrypoint and run can make use of them. + _ "k8s.io/client-go/plugin/pkg/client/auth" + + ctrl "sigs.k8s.io/controller-runtime" + + "github.com/go-logr/logr" + "github.com/radius-project/radius/pkg/armrpc/hostoptions" + "github.com/radius-project/radius/pkg/controller" + "github.com/radius-project/radius/pkg/trace" + "github.com/radius-project/radius/pkg/ucp/hosting" + "github.com/radius-project/radius/pkg/ucp/ucplog" + "github.com/spf13/cobra" + runtimelog "sigs.k8s.io/controller-runtime/pkg/log" +) + +var rootCmd = &cobra.Command{ + Use: "controller", + Short: "Radius Kubernetes controller", + Long: `Server process for Radius Kubernetes interoperability (controller).`, + RunE: func(cmd *cobra.Command, args []string) error { + configFilePath := cmd.Flag("config-file").Value.String() + tlsCertDir := cmd.Flag("cert-dir").Value.String() + + options, err := hostoptions.NewHostOptionsFromEnvironment(configFilePath) + if err != nil { + return err + } + + logger, flush, err := ucplog.NewLogger("controller", &options.Config.Logging) + if err != nil { + return err + } + defer flush() + + ctrl.SetLogger(logger) + runtimelog.SetLogger(logger) + + ctx := logr.NewContext(context.Background(), logger) + + logger.Info("Loaded options", "configfile", configFilePath) + + host := &hosting.Host{Services: []hosting.Service{ + &trace.Service{Options: options.Config.TracerProvider}, + &controller.Service{Options: options, TLSCertDir: tlsCertDir}, + }} + + return hosting.RunWithInterrupts(ctx, host) + }, +} + +func Execute() { + // Let users override the configuration via `--config-file`. + rootCmd.Flags().String("config-file", fmt.Sprintf("controller-%s.yaml", hostoptions.Environment()), "The service configuration file.") + rootCmd.Flags().String("cert-dir", "/var/tls/cert", "The directory containing the TLS certificates.") + + cobra.CheckErr(rootCmd.ExecuteContext(context.Background())) +} diff --git a/cmd/controller/main.go b/cmd/controller/main.go index aca000460b..2d9c6faad8 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -17,65 +17,13 @@ limitations under the License. package main import ( - "context" - "fmt" - "log" - "os" + "github.com/radius-project/radius/cmd/controller/cmd" // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) // to ensure that exec-entrypoint and run can make use of them. _ "k8s.io/client-go/plugin/pkg/client/auth" - - ctrl "sigs.k8s.io/controller-runtime" - - "github.com/go-logr/logr" - "github.com/radius-project/radius/pkg/armrpc/hostoptions" - "github.com/radius-project/radius/pkg/controller" - "github.com/radius-project/radius/pkg/trace" - "github.com/radius-project/radius/pkg/ucp/hosting" - "github.com/radius-project/radius/pkg/ucp/ucplog" - "github.com/spf13/pflag" - runtimelog "sigs.k8s.io/controller-runtime/pkg/log" ) func main() { - config := fmt.Sprintf("controller-%s.yaml", hostoptions.Environment()) - pflag.StringVar(&config, "config-file", config, "The service configuration file.") - - tlsCertDir := "/var/tls/cert" - pflag.StringVar(&tlsCertDir, "cert-dir", tlsCertDir, "The directory containing the TLS certificates.") - - pflag.Parse() - options, err := hostoptions.NewHostOptionsFromEnvironment(config) - if err != nil { - log.Fatal(err) //nolint:forbidigo // this is OK inside the main function. - } - - logger, flush, err := ucplog.NewLogger("controller", &options.Config.Logging) - if err != nil { - log.Fatal(err) //nolint:forbidigo // this is OK inside the main function. - } - defer flush() - - ctrl.SetLogger(logger) - runtimelog.SetLogger(logger) - - ctx := logr.NewContext(context.Background(), logger) - - logger.Info("Loaded options", "configfile", config) - - host := &hosting.Host{Services: []hosting.Service{ - &trace.Service{Options: options.Config.TracerProvider}, - &controller.Service{Options: options, TLSCertDir: tlsCertDir}, - }} - - err = hosting.RunWithInterrupts(ctx, host) - - // Finished shutting down. An error returned here is a failure to terminate - // gracefully, so just crash if that happens. - if err == nil { - os.Exit(0) //nolint:forbidigo // this is OK inside the main function. - } else { - panic(err) - } + cmd.Execute() } diff --git a/cmd/ucpd/cmd/root.go b/cmd/ucpd/cmd/root.go index 1f181d924c..c6672ea03f 100644 --- a/cmd/ucpd/cmd/root.go +++ b/cmd/ucpd/cmd/root.go @@ -18,13 +18,14 @@ package cmd import ( "context" - "log" + "fmt" "github.com/go-logr/logr" "github.com/spf13/cobra" etcdclient "go.etcd.io/etcd/client/v3" runtimelog "sigs.k8s.io/controller-runtime/pkg/log" + "github.com/radius-project/radius/pkg/armrpc/hostoptions" "github.com/radius-project/radius/pkg/ucp/dataprovider" "github.com/radius-project/radius/pkg/ucp/hosting" "github.com/radius-project/radius/pkg/ucp/server" @@ -36,14 +37,15 @@ var rootCmd = &cobra.Command{ Short: "UCP server", Long: `Server process for the Universal Control Plane (UCP).`, RunE: func(cmd *cobra.Command, args []string) error { - options, err := server.NewServerOptionsFromEnvironment() + configFilePath := cmd.Flag("config-file").Value.String() + options, err := server.NewServerOptionsFromEnvironment(configFilePath) if err != nil { return err } logger, flush, err := ucplog.NewLogger(ucplog.LoggerName, &options.LoggingOptions) if err != nil { - log.Fatal(err) //nolint:forbidigo // this is OK inside the main function. + return err } defer flush() @@ -66,11 +68,12 @@ var rootCmd = &cobra.Command{ } ctx := logr.NewContext(cmd.Context(), logger) - return hosting.RunWithInterrupts(ctx, host) }, } func Execute() { + // Let users override the configuration via `--config-file`. + rootCmd.Flags().String("config-file", fmt.Sprintf("radius-%s.yaml", hostoptions.Environment()), "The service configuration file.") cobra.CheckErr(rootCmd.ExecuteContext(context.Background())) } diff --git a/cmd/ucpd/ucp-self-hosted-dev.yaml b/cmd/ucpd/ucp-dev.yaml similarity index 100% rename from cmd/ucpd/ucp-self-hosted-dev.yaml rename to cmd/ucpd/ucp-dev.yaml diff --git a/deploy/Chart/templates/ucp/deployment.yaml b/deploy/Chart/templates/ucp/deployment.yaml index 0112c0d086..776b01ac7b 100644 --- a/deploy/Chart/templates/ucp/deployment.yaml +++ b/deploy/Chart/templates/ucp/deployment.yaml @@ -33,9 +33,9 @@ spec: containers: - name: ucp image: "{{ .Values.ucp.image }}:{{ .Values.ucp.tag | default $appversion }}" + args: + - --config-file=/etc/config/ucp-config.yaml env: - - name: UCP_CONFIG - value: /etc/config/ucp-config.yaml - name: BASE_PATH value: '/apis/api.ucp.dev/v1alpha3' # listen for APIService URLs - name: TLS_CERT_DIR diff --git a/docs/ucp/developer_guide.md b/docs/ucp/developer_guide.md index e0a6e2fde6..867d8d41ab 100644 --- a/docs/ucp/developer_guide.md +++ b/docs/ucp/developer_guide.md @@ -23,12 +23,13 @@ You can run cmd/ucp/main.go in vscode with the following configuration set in yo "env": { "BASE_PATH": "/apis/api.ucp.dev/v1alpha3", "PORT": "9000", - "UCP_CONFIG": "ucp-self-hosted-dev.yaml", "AWS_REGION": "{region}", "AWS_ACCESS_KEY_ID": "{aws key}", "AWS_SECRET_ACCESS_KEY": "{secret key}" }, "args": [ + "--config-file", + "${workspaceFolder}/cmd/ucpd/ucp-dev.yaml", ] }, ... diff --git a/pkg/ucp/server/server.go b/pkg/ucp/server/server.go index a24af00caf..421fd45d1c 100644 --- a/pkg/ucp/server/server.go +++ b/pkg/ucp/server/server.go @@ -72,21 +72,19 @@ type Options struct { const UCPProviderName = "System.Resources" // NewServerOptionsFromEnvironment creates a new Options struct from environment variables and returns it along with any errors. -func NewServerOptionsFromEnvironment() (Options, error) { +func NewServerOptionsFromEnvironment(configFilePath string) (Options, error) { basePath, ok := os.LookupEnv("BASE_PATH") if ok && len(basePath) > 0 && (!strings.HasPrefix(basePath, "/") || strings.HasSuffix(basePath, "/")) { return Options{}, errors.New("env: BASE_PATH must begin with '/' and must not end with '/'") } tlsCertDir := os.Getenv("TLS_CERT_DIR") - ucpConfigFile := os.Getenv("UCP_CONFIG") - port := os.Getenv("PORT") if port == "" { return Options{}, errors.New("UCP Port number must be set") } - opts, err := hostoptions.NewHostOptionsFromEnvironment(ucpConfigFile) + opts, err := hostoptions.NewHostOptionsFromEnvironment(configFilePath) if err != nil { return Options{}, err }