From d410ef343946c8afcd0a1792bdba6fe6f6388e6b Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Thu, 9 Nov 2023 16:50:27 -0800 Subject: [PATCH] K8s: Use grafana executable for standalone api service (#77904) Co-authored-by: Dan Cech --- .github/CODEOWNERS | 2 +- .gitignore | 2 +- Makefile | 6 +- pkg/build/cmd.go | 16 +--- pkg/build/grafana/build.go | 2 +- pkg/cmd/grafana-example-apiserver/main.go | 50 ------------- .../apiserver}/README.md | 4 +- pkg/cmd/grafana/apiserver/cmd.go | 75 +++++++++++++++++++ .../apiserver}/deploy/base/apiservice.yaml | 0 .../apiserver}/deploy/base/kustomization.yaml | 0 .../apiserver}/deploy/base/namespace.yaml | 0 .../deploy/darwin/kustomization.yaml | 0 .../apiserver}/deploy/darwin/service.yaml | 0 .../deploy/linux/kustomization.yaml | 0 .../apiserver}/deploy/linux/service.yaml | 0 .../apiserver}/server.go | 57 ++++++++------ pkg/cmd/grafana/main.go | 13 ++++ 17 files changed, 133 insertions(+), 94 deletions(-) delete mode 100644 pkg/cmd/grafana-example-apiserver/main.go rename pkg/cmd/{grafana-example-apiserver => grafana/apiserver}/README.md (95%) create mode 100644 pkg/cmd/grafana/apiserver/cmd.go rename pkg/cmd/{grafana-example-apiserver => grafana/apiserver}/deploy/base/apiservice.yaml (100%) rename pkg/cmd/{grafana-example-apiserver => grafana/apiserver}/deploy/base/kustomization.yaml (100%) rename pkg/cmd/{grafana-example-apiserver => grafana/apiserver}/deploy/base/namespace.yaml (100%) rename pkg/cmd/{grafana-example-apiserver => grafana/apiserver}/deploy/darwin/kustomization.yaml (100%) rename pkg/cmd/{grafana-example-apiserver => grafana/apiserver}/deploy/darwin/service.yaml (100%) rename pkg/cmd/{grafana-example-apiserver => grafana/apiserver}/deploy/linux/kustomization.yaml (100%) rename pkg/cmd/{grafana-example-apiserver => grafana/apiserver}/deploy/linux/service.yaml (100%) rename pkg/cmd/{grafana-example-apiserver => grafana/apiserver}/server.go (72%) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c37bd586f41..7abd2692bdb 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -69,7 +69,7 @@ /pkg/apis/ @grafana/grafana-app-platform-squad /pkg/bus/ @grafana/backend-platform /pkg/cmd/ @grafana/backend-platform -/pkg/cmd/grafana-example-apiserver @grafana/grafana-app-platform-squad +/pkg/cmd/grafana/apiserver @grafana/grafana-app-platform-squad /pkg/components/apikeygen/ @grafana/identity-access-team /pkg/components/satokengen/ @grafana/identity-access-team /pkg/components/dashdiffs/ @grafana/backend-platform diff --git a/.gitignore b/.gitignore index 76bd2088512..d8861ecbb76 100644 --- a/.gitignore +++ b/.gitignore @@ -78,7 +78,7 @@ public/css/*.min.css /data/* /bin/* -# any certificates generated by grafana-example-apiserver +# any certificates generated by grafana apiserver apiserver.local.config/ # devenv diff --git a/Makefile b/Makefile index 81bca4a149a..686e7f55b4d 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ WIRE_TAGS = "oss" -include local/Makefile include .bingo/Variables.mk -.PHONY: all deps-go deps-js deps build-go build-backend build-example-apiserver build-server build-cli build-js build build-docker-full build-docker-full-ubuntu lint-go golangci-lint test-go test-js gen-ts test run run-frontend clean devenv devenv-down protobuf drone help gen-go gen-cue fix-cue +.PHONY: all deps-go deps-js deps build-go build-backend build-server build-cli build-js build build-docker-full build-docker-full-ubuntu lint-go golangci-lint test-go test-js gen-ts test run run-frontend clean devenv devenv-down protobuf drone help gen-go gen-cue fix-cue GO = go GO_FILES ?= ./pkg/... @@ -132,10 +132,6 @@ build-server: ## Build Grafana server. @echo "build server" $(GO) run build.go $(GO_BUILD_FLAGS) build-server -build-example-apiserver: ## Build Grafana example-apiserver application. - @echo "build grafana-cli" - $(GO) run build.go $(GO_BUILD_FLAGS) build-example-apiserver - build-cli: ## Build Grafana CLI application. @echo "build grafana-cli" $(GO) run build.go $(GO_BUILD_FLAGS) build-cli diff --git a/pkg/build/cmd.go b/pkg/build/cmd.go index 34d1e037d9a..fa98316e9c2 100644 --- a/pkg/build/cmd.go +++ b/pkg/build/cmd.go @@ -17,13 +17,12 @@ const ( GoOSWindows = "windows" GoOSLinux = "linux" - BackendBinary = "grafana" - ExampleAPIServerBinary = "grafana-example-apiserver" - ServerBinary = "grafana-server" - CLIBinary = "grafana-cli" + BackendBinary = "grafana" + ServerBinary = "grafana-server" + CLIBinary = "grafana-cli" ) -var binaries = []string{BackendBinary, ExampleAPIServerBinary, ServerBinary, CLIBinary} +var binaries = []string{BackendBinary, ServerBinary, CLIBinary} func logError(message string, err error) int { log.Println(message, err) @@ -86,13 +85,6 @@ func RunCmd() int { return 1 } - case "build-example-apiserver": - clean(opts) - if err := doBuild("grafana-example-apiserver", "./pkg/cmd/grafana-example-apiserver", opts); err != nil { - log.Println(err) - return 1 - } - case "build-cli": clean(opts) if err := doBuild("grafana-cli", "./pkg/cmd/grafana-cli", opts); err != nil { diff --git a/pkg/build/grafana/build.go b/pkg/build/grafana/build.go index 084b6c5f624..586b2d22839 100644 --- a/pkg/build/grafana/build.go +++ b/pkg/build/grafana/build.go @@ -12,7 +12,7 @@ import ( "github.com/grafana/grafana/pkg/build/golangutils" ) -var binaries = []string{"grafana", "grafana-example-apiserver", "grafana-server", "grafana-cli"} +var binaries = []string{"grafana", "grafana-server", "grafana-cli"} const ( SuffixEnterprise2 = "-enterprise2" diff --git a/pkg/cmd/grafana-example-apiserver/main.go b/pkg/cmd/grafana-example-apiserver/main.go deleted file mode 100644 index 92a163798f8..00000000000 --- a/pkg/cmd/grafana-example-apiserver/main.go +++ /dev/null @@ -1,50 +0,0 @@ -package main - -import ( - "os" - - "github.com/spf13/cobra" - genericapiserver "k8s.io/apiserver/pkg/server" - "k8s.io/component-base/cli" -) - -func NewCommandStartExampleAPIServer(defaults *ExampleServerOptions, stopCh <-chan struct{}) *cobra.Command { - o := *defaults - cmd := &cobra.Command{ - Short: "Launch the example API server", - Long: "Launch the example API server", - RunE: func(c *cobra.Command, args []string) error { - if err := o.Complete(); err != nil { - return err - } - - config, err := o.Config() - if err != nil { - return err - } - - if err := o.RunExampleServer(config, stopCh); err != nil { - return err - } - return nil - }, - } - - flags := cmd.Flags() - o.RecommendedOptions.AddFlags(flags) - - return cmd -} - -func main() { - stopCh := genericapiserver.SetupSignalHandler() - options, err := NewExampleServerOptions(os.Stdout, os.Stderr) - if err != nil { - panic(err) - } - - cmd := NewCommandStartExampleAPIServer(options, stopCh) - - code := cli.Run(cmd) - os.Exit(code) -} diff --git a/pkg/cmd/grafana-example-apiserver/README.md b/pkg/cmd/grafana/apiserver/README.md similarity index 95% rename from pkg/cmd/grafana-example-apiserver/README.md rename to pkg/cmd/grafana/apiserver/README.md index 8b1b9322c15..1c13a23cc66 100644 --- a/pkg/cmd/grafana-example-apiserver/README.md +++ b/pkg/cmd/grafana/apiserver/README.md @@ -1,4 +1,4 @@ -# grafana-example-apiserver +# grafana apiserver (standalone) The example-apiserver closely resembles the [sample-apiserver](https://github.com/kubernetes/sample-apiserver/tree/master) project in code and thus @@ -19,7 +19,7 @@ can be used as a root server for this example-apiserver (in aggregated mode). He kind cluster and that you can provide its kubeconfig in the parameters to the example-apiserver. ```shell -go run ./pkg/cmd/grafana-example-apiserver \ +go run ./pkg/cmd/grafana apiserver example.grafana.app\ --authentication-kubeconfig ~/.kube/config \ --authorization-kubeconfig ~/.kube/config \ --kubeconfig ~/.kube/config \ diff --git a/pkg/cmd/grafana/apiserver/cmd.go b/pkg/cmd/grafana/apiserver/cmd.go new file mode 100644 index 00000000000..a11628ce1e1 --- /dev/null +++ b/pkg/cmd/grafana/apiserver/cmd.go @@ -0,0 +1,75 @@ +package apiserver + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" + genericapiserver "k8s.io/apiserver/pkg/server" + "k8s.io/apiserver/pkg/server/options" + "k8s.io/component-base/cli" +) + +func newCommandStartExampleAPIServer(o *ExampleServerOptions, stopCh <-chan struct{}) *cobra.Command { + // While this exists as an experimental feature, we require adding the scarry looking command line + devAcknowledgementFlag := "grafana-enable-experimental-apiserver" + devAcknowledgementNotice := "The apiserver command is in heavy development. The entire setup is subject to change without notice" + + cmd := &cobra.Command{ + Use: "apiserver [api group(s)]", + Short: "Run the grafana apiserver", + Long: "Run a standalone kubernetes based apiserver that can be aggregated by a root apiserver. " + + devAcknowledgementNotice, + Example: fmt.Sprintf("grafana apiserver example.grafana.app --%s", devAcknowledgementFlag), + PersistentPreRun: func(cmd *cobra.Command, args []string) { + ok, err := cmd.Flags().GetBool(devAcknowledgementFlag) + if !ok || err != nil { + fmt.Printf("requires running with the flag: --%s\n\n%s\n\n", + devAcknowledgementFlag, devAcknowledgementNotice) + os.Exit(1) + } + }, + RunE: func(c *cobra.Command, args []string) error { + // Load each group from the args + if err := o.LoadAPIGroupBuilders(args[1:]); err != nil { + return err + } + + // Finish the config (applies all defaults) + if err := o.Complete(); err != nil { + return err + } + + config, err := o.Config() + if err != nil { + return err + } + + if err := o.RunExampleServer(config, stopCh); err != nil { + return err + } + return nil + }, + } + + // Register grafana flags + cmd.PersistentFlags().Bool(devAcknowledgementFlag, false, devAcknowledgementNotice) + + // Register standard k8s flags with the command line + o.RecommendedOptions = options.NewRecommendedOptions( + defaultEtcdPathPrefix, + Codecs.LegacyCodec(), // the codec is passed to etcd and not used + ) + o.RecommendedOptions.AddFlags(cmd.Flags()) + + return cmd +} + +func RunCLI() int { + stopCh := genericapiserver.SetupSignalHandler() + + options := newExampleServerOptions(os.Stdout, os.Stderr) + cmd := newCommandStartExampleAPIServer(options, stopCh) + + return cli.Run(cmd) +} diff --git a/pkg/cmd/grafana-example-apiserver/deploy/base/apiservice.yaml b/pkg/cmd/grafana/apiserver/deploy/base/apiservice.yaml similarity index 100% rename from pkg/cmd/grafana-example-apiserver/deploy/base/apiservice.yaml rename to pkg/cmd/grafana/apiserver/deploy/base/apiservice.yaml diff --git a/pkg/cmd/grafana-example-apiserver/deploy/base/kustomization.yaml b/pkg/cmd/grafana/apiserver/deploy/base/kustomization.yaml similarity index 100% rename from pkg/cmd/grafana-example-apiserver/deploy/base/kustomization.yaml rename to pkg/cmd/grafana/apiserver/deploy/base/kustomization.yaml diff --git a/pkg/cmd/grafana-example-apiserver/deploy/base/namespace.yaml b/pkg/cmd/grafana/apiserver/deploy/base/namespace.yaml similarity index 100% rename from pkg/cmd/grafana-example-apiserver/deploy/base/namespace.yaml rename to pkg/cmd/grafana/apiserver/deploy/base/namespace.yaml diff --git a/pkg/cmd/grafana-example-apiserver/deploy/darwin/kustomization.yaml b/pkg/cmd/grafana/apiserver/deploy/darwin/kustomization.yaml similarity index 100% rename from pkg/cmd/grafana-example-apiserver/deploy/darwin/kustomization.yaml rename to pkg/cmd/grafana/apiserver/deploy/darwin/kustomization.yaml diff --git a/pkg/cmd/grafana-example-apiserver/deploy/darwin/service.yaml b/pkg/cmd/grafana/apiserver/deploy/darwin/service.yaml similarity index 100% rename from pkg/cmd/grafana-example-apiserver/deploy/darwin/service.yaml rename to pkg/cmd/grafana/apiserver/deploy/darwin/service.yaml diff --git a/pkg/cmd/grafana-example-apiserver/deploy/linux/kustomization.yaml b/pkg/cmd/grafana/apiserver/deploy/linux/kustomization.yaml similarity index 100% rename from pkg/cmd/grafana-example-apiserver/deploy/linux/kustomization.yaml rename to pkg/cmd/grafana/apiserver/deploy/linux/kustomization.yaml diff --git a/pkg/cmd/grafana-example-apiserver/deploy/linux/service.yaml b/pkg/cmd/grafana/apiserver/deploy/linux/service.yaml similarity index 100% rename from pkg/cmd/grafana-example-apiserver/deploy/linux/service.yaml rename to pkg/cmd/grafana/apiserver/deploy/linux/service.yaml diff --git a/pkg/cmd/grafana-example-apiserver/server.go b/pkg/cmd/grafana/apiserver/server.go similarity index 72% rename from pkg/cmd/grafana-example-apiserver/server.go rename to pkg/cmd/grafana/apiserver/server.go index 5d4aac8947c..a5b251f8c80 100644 --- a/pkg/cmd/grafana-example-apiserver/server.go +++ b/pkg/cmd/grafana/apiserver/server.go @@ -1,11 +1,11 @@ -package main +package apiserver import ( "fmt" "io" "net" - exampleAPI "github.com/grafana/grafana/pkg/registry/apis/example" + "github.com/grafana/grafana/pkg/registry/apis/example" grafanaAPIServer "github.com/grafana/grafana/pkg/services/grafana-apiserver" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -43,34 +43,47 @@ func init() { // ExampleServerOptions contains the state for the apiserver type ExampleServerOptions struct { + builders []grafanaAPIServer.APIGroupBuilder RecommendedOptions *options.RecommendedOptions - Builders []grafanaAPIServer.APIGroupBuilder AlternateDNS []string StdOut io.Writer StdErr io.Writer } -func NewExampleServerOptions(out, errOut io.Writer) (*ExampleServerOptions, error) { - builder := &exampleAPI.TestingAPIBuilder{} - - // Install schema - if err := builder.InstallSchema(Scheme); err != nil { - return nil, err - } - +func newExampleServerOptions(out, errOut io.Writer) *ExampleServerOptions { return &ExampleServerOptions{ - Builders: []grafanaAPIServer.APIGroupBuilder{builder}, - RecommendedOptions: options.NewRecommendedOptions( - defaultEtcdPathPrefix, - Codecs.LegacyCodec(builder.GetGroupVersion()), - ), StdOut: out, StdErr: errOut, - }, nil + } } -func (o ExampleServerOptions) Config() (*genericapiserver.RecommendedConfig, error) { +func (o *ExampleServerOptions) LoadAPIGroupBuilders(args []string) error { + o.builders = []grafanaAPIServer.APIGroupBuilder{} + for _, g := range args { + switch g { + // No dependencies for testing + case "example.grafana.app": + o.builders = append(o.builders, &example.TestingAPIBuilder{}) + default: + return fmt.Errorf("unknown group: %s", g) + } + } + + if len(o.builders) < 1 { + return fmt.Errorf("expected group name(s) in the command line arguments") + } + + // Install schemas + for _, b := range o.builders { + if err := b.InstallSchema(Scheme); err != nil { + return err + } + } + return nil +} + +func (o *ExampleServerOptions) Config() (*genericapiserver.RecommendedConfig, error) { if err := o.RecommendedOptions.SecureServing.MaybeDefaultWithSelfSignedCerts("localhost", o.AlternateDNS, []net.IP{netutils.ParseIPSloppy("127.0.0.1")}); err != nil { return nil, fmt.Errorf("error creating self-signed certificates: %v", err) } @@ -94,18 +107,18 @@ func (o ExampleServerOptions) Config() (*genericapiserver.RecommendedConfig, err // Validate validates ExampleServerOptions // NOTE: we don't call validate on the top level recommended options as it doesn't like skipping etcd-servers // the function is left here for troubleshooting any other config issues -func (o ExampleServerOptions) Validate(args []string) error { +func (o *ExampleServerOptions) Validate(args []string) error { errors := []error{} errors = append(errors, o.RecommendedOptions.Validate()...) return utilerrors.NewAggregate(errors) } // Complete fills in fields required to have valid data -func (o ExampleServerOptions) Complete() error { +func (o *ExampleServerOptions) Complete() error { return nil } -func (o ExampleServerOptions) RunExampleServer(config *genericapiserver.RecommendedConfig, stopCh <-chan struct{}) error { +func (o *ExampleServerOptions) RunExampleServer(config *genericapiserver.RecommendedConfig, stopCh <-chan struct{}) error { delegationTarget := genericapiserver.NewEmptyDelegate() completedConfig := config.Complete() server, err := completedConfig.New("example-apiserver", delegationTarget) @@ -114,7 +127,7 @@ func (o ExampleServerOptions) RunExampleServer(config *genericapiserver.Recommen } // Install the API Group+version - for _, b := range o.Builders { + for _, b := range o.builders { g, err := b.GetAPIGroupInfo(Scheme, Codecs, completedConfig.RESTOptionsGetter) if err != nil { return err diff --git a/pkg/cmd/grafana/main.go b/pkg/cmd/grafana/main.go index 48ba9586f4f..e543ee0fd10 100644 --- a/pkg/cmd/grafana/main.go +++ b/pkg/cmd/grafana/main.go @@ -9,6 +9,7 @@ import ( gcli "github.com/grafana/grafana/pkg/cmd/grafana-cli/commands" gsrv "github.com/grafana/grafana/pkg/cmd/grafana-server/commands" + "github.com/grafana/grafana/pkg/cmd/grafana/apiserver" ) // The following variables cannot be constants, since they can be overridden through the -X link flag @@ -32,6 +33,18 @@ func main() { Commands: []*cli.Command{ gcli.CLICommand(version), gsrv.ServerCommand(version, commit, enterpriseCommit, buildBranch, buildstamp), + { + // The kubernetes standalone apiserver service runner + Name: "apiserver", + Usage: "run a standalone api service (experimental)", + // Skip parsing flags because the command line is actually managed by cobra + SkipFlagParsing: true, + Action: func(context *cli.Context) error { + // exit here because apiserver handles its own error output + os.Exit(apiserver.RunCLI()) + return nil + }, + }, }, CommandNotFound: cmdNotFound, EnableBashCompletion: true,