@ -4,21 +4,30 @@ import (
"fmt"
"io"
"net"
"github.com/grafana/grafana/pkg/registry/apis/example"
grafanaAPIServer "github.com/grafana/grafana/pkg/services/grafana-apiserver"
"path"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
openapinamer "k8s.io/apiserver/pkg/endpoints/openapi"
genericapiserver "k8s.io/apiserver/pkg/server"
"k8s.io/apiserver/pkg/server/options"
"k8s.io/apiserver/pkg/util/openapi"
"k8s.io/client-go/tools/clientcmd"
netutils "k8s.io/utils/net"
"github.com/grafana/grafana/pkg/services/grafana-apiserver/utils"
"github.com/grafana/grafana/pkg/registry/apis/example"
grafanaAPIServer "github.com/grafana/grafana/pkg/services/grafana-apiserver"
)
const defaultEtcdPathPrefix = "/registry/example.grafana.app"
const (
defaultEtcdPathPrefix = "/registry/grafana.app"
dataPath = "data/grafana-apiserver" // same as grafana core
)
var (
Scheme = runtime . NewScheme ( )
@ -41,8 +50,8 @@ func init() {
Scheme . AddUnversionedTypes ( unversionedVersion , unversionedTypes ... )
}
// Example ServerOptions contains the state for the apiserver
type Example ServerOptions struct {
// API ServerOptions contains the state for the apiserver
type API ServerOptions struct {
builders [ ] grafanaAPIServer . APIGroupBuilder
RecommendedOptions * options . RecommendedOptions
AlternateDNS [ ] string
@ -51,20 +60,20 @@ type ExampleServerOptions struct {
StdErr io . Writer
}
func newExample ServerOptions ( out , errOut io . Writer ) * Example ServerOptions {
return & Example ServerOptions{
func newAPI ServerOptions ( out , errOut io . Writer ) * API ServerOptions {
return & API ServerOptions{
StdOut : out ,
StdErr : errOut ,
}
}
func ( o * Example ServerOptions) LoadAPIGroupBuilders ( args [ ] string ) error {
func ( o * API ServerOptions) 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 { } )
o . builders = append ( o . builders , example . NewTestingAPIBuilder ( ) )
default :
return fmt . Errorf ( "unknown group: %s" , g )
}
@ -83,8 +92,49 @@ func (o *ExampleServerOptions) LoadAPIGroupBuilders(args []string) error {
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 {
// A copy of ApplyTo in recommended.go, but for >= 0.28, server pkg in apiserver does a bit extra causing
// a panic when CoreAPI is set to nil
func ( o * APIServerOptions ) ModifiedApplyTo ( config * genericapiserver . RecommendedConfig ) error {
if err := o . RecommendedOptions . Etcd . ApplyTo ( & config . Config ) ; err != nil {
return err
}
if err := o . RecommendedOptions . EgressSelector . ApplyTo ( & config . Config ) ; err != nil {
return err
}
if err := o . RecommendedOptions . Traces . ApplyTo ( config . Config . EgressSelector , & config . Config ) ; err != nil {
return err
}
if err := o . RecommendedOptions . SecureServing . ApplyTo ( & config . Config . SecureServing , & config . Config . LoopbackClientConfig ) ; err != nil {
return err
}
if err := o . RecommendedOptions . Authentication . ApplyTo ( & config . Config . Authentication , config . SecureServing , config . OpenAPIConfig ) ; err != nil {
return err
}
if err := o . RecommendedOptions . Authorization . ApplyTo ( & config . Config . Authorization ) ; err != nil {
return err
}
if err := o . RecommendedOptions . Audit . ApplyTo ( & config . Config ) ; err != nil {
return err
}
if err := o . RecommendedOptions . Features . ApplyTo ( & config . Config ) ; err != nil {
return err
}
if err := o . RecommendedOptions . CoreAPI . ApplyTo ( config ) ; err != nil {
return err
}
_ , err := o . RecommendedOptions . ExtraAdmissionInitializers ( config )
if err != nil {
return err
}
return nil
}
func ( o * APIServerOptions ) 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 )
}
@ -92,33 +142,55 @@ func (o *ExampleServerOptions) Config() (*genericapiserver.RecommendedConfig, er
o . RecommendedOptions . Authorization . RemoteKubeConfigFileOptional = true
o . RecommendedOptions . Admission = nil
o . RecommendedOptions . CoreAPI = nil
o . RecommendedOptions . Etcd = nil
if o . RecommendedOptions . CoreAPI . CoreAPIKubeconfigPath == "" {
o . RecommendedOptions . CoreAPI = nil
}
serverConfig := genericapiserver . NewRecommendedConfig ( Codecs )
if err := o . RecommendedOptions . ApplyTo ( serverConfig ) ; err != nil {
return nil , err
if o . RecommendedOptions . CoreAPI == nil {
if err := o . ModifiedApplyTo ( serverConfig ) ; err != nil {
return nil , err
}
} else {
if err := o . RecommendedOptions . ApplyTo ( serverConfig ) ; err != nil {
return nil , err
}
}
// Add OpenAPI specs for each group+version
defsGetter := grafanaAPIServer . GetOpenAPIDefinitions ( o . builders )
serverConfig . OpenAPIConfig = genericapiserver . DefaultOpenAPIConfig (
openapi . GetOpenAPIDefinitionsWithoutDisabledFeatures ( defsGetter ) ,
openapinamer . NewDefinitionNamer ( Scheme ) )
serverConfig . OpenAPIV3Config = genericapiserver . DefaultOpenAPIV3Config (
openapi . GetOpenAPIDefinitionsWithoutDisabledFeatures ( defsGetter ) ,
openapinamer . NewDefinitionNamer ( Scheme ) )
// Add the custom routes to service discovery
serverConfig . OpenAPIV3Config . PostProcessSpec3 = grafanaAPIServer . GetOpenAPIPostProcessor ( o . builders )
return serverConfig , nil
}
// Validate validates ExampleServerOptions
// Validate validates API ServerOptions
// 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 * API ServerOptions) 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 * Example ServerOptions) Complete ( ) error {
func ( o * API ServerOptions) Complete ( ) error {
return nil
}
func ( o * ExampleServerOptions ) RunExample Server( config * genericapiserver . RecommendedConfig , stopCh <- chan struct { } ) error {
func ( o * APIServerOptions ) RunAPI Server( config * genericapiserver . RecommendedConfig , stopCh <- chan struct { } ) error {
delegationTarget := genericapiserver . NewEmptyDelegate ( )
completedConfig := config . Complete ( )
server , err := completedConfig . New ( "example-apiserver" , delegationTarget )
@ -141,5 +213,15 @@ func (o *ExampleServerOptions) RunExampleServer(config *genericapiserver.Recomme
}
}
// in standalone mode, write the local config to disk
if o . RecommendedOptions . CoreAPI == nil {
if err = clientcmd . WriteToFile (
utils . FormatKubeConfig ( server . LoopbackClientConfig ) ,
path . Join ( dataPath , "grafana.kubeconfig" ) ,
) ; err != nil {
return err
}
}
return server . PrepareRun ( ) . Run ( stopCh )
}