| /* |
| Copyright 2016 The Kubernetes 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 server |
| |
| import ( |
| "fmt" |
| "io" |
| "net" |
| |
| "github.com/spf13/cobra" |
| |
| utilerrors "k8s.io/apimachinery/pkg/util/errors" |
| "k8s.io/apiserver/pkg/admission" |
| genericapiserver "k8s.io/apiserver/pkg/server" |
| genericoptions "k8s.io/apiserver/pkg/server/options" |
| "k8s.io/sample-apiserver/pkg/admission/plugin/banflunder" |
| "k8s.io/sample-apiserver/pkg/admission/wardleinitializer" |
| "k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1" |
| "k8s.io/sample-apiserver/pkg/apiserver" |
| clientset "k8s.io/sample-apiserver/pkg/client/clientset/internalversion" |
| informers "k8s.io/sample-apiserver/pkg/client/informers/internalversion" |
| ) |
| |
| const defaultEtcdPathPrefix = "/registry/wardle.kubernetes.io" |
| |
| type WardleServerOptions struct { |
| RecommendedOptions *genericoptions.RecommendedOptions |
| |
| SharedInformerFactory informers.SharedInformerFactory |
| StdOut io.Writer |
| StdErr io.Writer |
| } |
| |
| func NewWardleServerOptions(out, errOut io.Writer) *WardleServerOptions { |
| o := &WardleServerOptions{ |
| RecommendedOptions: genericoptions.NewRecommendedOptions( |
| defaultEtcdPathPrefix, |
| apiserver.Codecs.LegacyCodec(v1alpha1.SchemeGroupVersion), |
| genericoptions.NewProcessInfo("wardle-apiserver", "wardle"), |
| ), |
| |
| StdOut: out, |
| StdErr: errOut, |
| } |
| |
| return o |
| } |
| |
| // NewCommandStartWardleServer provides a CLI handler for 'start master' command |
| // with a default WardleServerOptions. |
| func NewCommandStartWardleServer(defaults *WardleServerOptions, stopCh <-chan struct{}) *cobra.Command { |
| o := *defaults |
| cmd := &cobra.Command{ |
| Short: "Launch a wardle API server", |
| Long: "Launch a wardle API server", |
| RunE: func(c *cobra.Command, args []string) error { |
| if err := o.Complete(); err != nil { |
| return err |
| } |
| if err := o.Validate(args); err != nil { |
| return err |
| } |
| if err := o.RunWardleServer(stopCh); err != nil { |
| return err |
| } |
| return nil |
| }, |
| } |
| |
| flags := cmd.Flags() |
| o.RecommendedOptions.AddFlags(flags) |
| |
| return cmd |
| } |
| |
| func (o WardleServerOptions) Validate(args []string) error { |
| errors := []error{} |
| errors = append(errors, o.RecommendedOptions.Validate()...) |
| return utilerrors.NewAggregate(errors) |
| } |
| |
| func (o *WardleServerOptions) Complete() error { |
| // register admission plugins |
| banflunder.Register(o.RecommendedOptions.Admission.Plugins) |
| |
| // add admisison plugins to the RecommendedPluginOrder |
| o.RecommendedOptions.Admission.RecommendedPluginOrder = append(o.RecommendedOptions.Admission.RecommendedPluginOrder, "BanFlunder") |
| |
| return nil |
| } |
| |
| func (o *WardleServerOptions) Config() (*apiserver.Config, error) { |
| // TODO have a "real" external address |
| if err := o.RecommendedOptions.SecureServing.MaybeDefaultWithSelfSignedCerts("localhost", nil, []net.IP{net.ParseIP("127.0.0.1")}); err != nil { |
| return nil, fmt.Errorf("error creating self-signed certificates: %v", err) |
| } |
| |
| o.RecommendedOptions.ExtraAdmissionInitializers = func(c *genericapiserver.RecommendedConfig) ([]admission.PluginInitializer, error) { |
| client, err := clientset.NewForConfig(c.LoopbackClientConfig) |
| if err != nil { |
| return nil, err |
| } |
| informerFactory := informers.NewSharedInformerFactory(client, c.LoopbackClientConfig.Timeout) |
| o.SharedInformerFactory = informerFactory |
| return []admission.PluginInitializer{wardleinitializer.New(informerFactory)}, nil |
| } |
| |
| serverConfig := genericapiserver.NewRecommendedConfig(apiserver.Codecs) |
| if err := o.RecommendedOptions.ApplyTo(serverConfig, apiserver.Scheme); err != nil { |
| return nil, err |
| } |
| |
| config := &apiserver.Config{ |
| GenericConfig: serverConfig, |
| ExtraConfig: apiserver.ExtraConfig{}, |
| } |
| return config, nil |
| } |
| |
| func (o WardleServerOptions) RunWardleServer(stopCh <-chan struct{}) error { |
| config, err := o.Config() |
| if err != nil { |
| return err |
| } |
| |
| server, err := config.Complete().New() |
| if err != nil { |
| return err |
| } |
| |
| server.GenericAPIServer.AddPostStartHook("start-sample-server-informers", func(context genericapiserver.PostStartHookContext) error { |
| config.GenericConfig.SharedInformerFactory.Start(context.StopCh) |
| o.SharedInformerFactory.Start(context.StopCh) |
| return nil |
| }) |
| |
| return server.GenericAPIServer.PrepareRun().Run(stopCh) |
| } |