199 lines
7.4 KiB
Go
199 lines
7.4 KiB
Go
/*
|
|
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 options
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"github.com/spf13/pflag"
|
|
|
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
"k8s.io/apimachinery/pkg/util/sets"
|
|
"k8s.io/apiserver/pkg/registry/generic"
|
|
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
|
"k8s.io/apiserver/pkg/server"
|
|
"k8s.io/apiserver/pkg/server/healthz"
|
|
serverstorage "k8s.io/apiserver/pkg/server/storage"
|
|
"k8s.io/apiserver/pkg/storage/etcd3/preflight"
|
|
"k8s.io/apiserver/pkg/storage/storagebackend"
|
|
)
|
|
|
|
type EtcdOptions struct {
|
|
StorageConfig storagebackend.Config
|
|
EncryptionProviderConfigFilepath string
|
|
|
|
EtcdServersOverrides []string
|
|
|
|
// To enable protobuf as storage format, it is enough
|
|
// to set it to "application/vnd.kubernetes.protobuf".
|
|
DefaultStorageMediaType string
|
|
DeleteCollectionWorkers int
|
|
EnableGarbageCollection bool
|
|
|
|
// Set EnableWatchCache to false to disable all watch caches
|
|
EnableWatchCache bool
|
|
// Set DefaultWatchCacheSize to zero to disable watch caches for those resources that have no explicit cache size set
|
|
DefaultWatchCacheSize int
|
|
}
|
|
|
|
var storageTypes = sets.NewString(
|
|
storagebackend.StorageTypeUnset,
|
|
storagebackend.StorageTypeETCD2,
|
|
storagebackend.StorageTypeETCD3,
|
|
)
|
|
|
|
func NewEtcdOptions(backendConfig *storagebackend.Config) *EtcdOptions {
|
|
return &EtcdOptions{
|
|
StorageConfig: *backendConfig,
|
|
DefaultStorageMediaType: "application/json",
|
|
DeleteCollectionWorkers: 1,
|
|
EnableGarbageCollection: true,
|
|
EnableWatchCache: true,
|
|
DefaultWatchCacheSize: 100,
|
|
}
|
|
}
|
|
|
|
func (s *EtcdOptions) Validate() []error {
|
|
allErrors := []error{}
|
|
if len(s.StorageConfig.ServerList) == 0 {
|
|
allErrors = append(allErrors, fmt.Errorf("--etcd-servers must be specified"))
|
|
}
|
|
|
|
if !storageTypes.Has(s.StorageConfig.Type) {
|
|
allErrors = append(allErrors, fmt.Errorf("--storage-backend invalid, must be 'etcd3' or 'etcd2'. If not specified, it will default to 'etcd3'"))
|
|
}
|
|
|
|
return allErrors
|
|
}
|
|
|
|
// AddEtcdFlags adds flags related to etcd storage for a specific APIServer to the specified FlagSet
|
|
func (s *EtcdOptions) AddFlags(fs *pflag.FlagSet) {
|
|
fs.StringSliceVar(&s.EtcdServersOverrides, "etcd-servers-overrides", s.EtcdServersOverrides, ""+
|
|
"Per-resource etcd servers overrides, comma separated. The individual override "+
|
|
"format: group/resource#servers, where servers are http://ip:port, semicolon separated.")
|
|
|
|
fs.StringVar(&s.DefaultStorageMediaType, "storage-media-type", s.DefaultStorageMediaType, ""+
|
|
"The media type to use to store objects in storage. "+
|
|
"Some resources or storage backends may only support a specific media type and will ignore this setting.")
|
|
fs.IntVar(&s.DeleteCollectionWorkers, "delete-collection-workers", s.DeleteCollectionWorkers,
|
|
"Number of workers spawned for DeleteCollection call. These are used to speed up namespace cleanup.")
|
|
|
|
fs.BoolVar(&s.EnableGarbageCollection, "enable-garbage-collector", s.EnableGarbageCollection, ""+
|
|
"Enables the generic garbage collector. MUST be synced with the corresponding flag "+
|
|
"of the kube-controller-manager.")
|
|
|
|
// TODO: enable cache in integration tests.
|
|
fs.BoolVar(&s.EnableWatchCache, "watch-cache", s.EnableWatchCache,
|
|
"Enable watch caching in the apiserver")
|
|
|
|
fs.StringVar(&s.StorageConfig.Type, "storage-backend", s.StorageConfig.Type,
|
|
"The storage backend for persistence. Options: 'etcd3' (default), 'etcd2'.")
|
|
|
|
fs.IntVar(&s.StorageConfig.DeserializationCacheSize, "deserialization-cache-size", s.StorageConfig.DeserializationCacheSize,
|
|
"Number of deserialized json objects to cache in memory.")
|
|
|
|
fs.StringSliceVar(&s.StorageConfig.ServerList, "etcd-servers", s.StorageConfig.ServerList,
|
|
"List of etcd servers to connect with (scheme://ip:port), comma separated.")
|
|
|
|
fs.StringVar(&s.StorageConfig.Prefix, "etcd-prefix", s.StorageConfig.Prefix,
|
|
"The prefix to prepend to all resource paths in etcd.")
|
|
|
|
fs.StringVar(&s.StorageConfig.KeyFile, "etcd-keyfile", s.StorageConfig.KeyFile,
|
|
"SSL key file used to secure etcd communication.")
|
|
|
|
fs.StringVar(&s.StorageConfig.CertFile, "etcd-certfile", s.StorageConfig.CertFile,
|
|
"SSL certification file used to secure etcd communication.")
|
|
|
|
fs.StringVar(&s.StorageConfig.CAFile, "etcd-cafile", s.StorageConfig.CAFile,
|
|
"SSL Certificate Authority file used to secure etcd communication.")
|
|
|
|
fs.BoolVar(&s.StorageConfig.Quorum, "etcd-quorum-read", s.StorageConfig.Quorum,
|
|
"If true, enable quorum read.")
|
|
|
|
fs.StringVar(&s.EncryptionProviderConfigFilepath, "experimental-encryption-provider-config", s.EncryptionProviderConfigFilepath,
|
|
"The file containing configuration for encryption providers to be used for storing secrets in etcd")
|
|
}
|
|
|
|
func (s *EtcdOptions) ApplyTo(c *server.Config) error {
|
|
s.addEtcdHealthEndpoint(c)
|
|
c.RESTOptionsGetter = &SimpleRestOptionsFactory{Options: *s}
|
|
return nil
|
|
}
|
|
|
|
func (s *EtcdOptions) ApplyWithStorageFactoryTo(factory serverstorage.StorageFactory, c *server.Config) error {
|
|
s.addEtcdHealthEndpoint(c)
|
|
c.RESTOptionsGetter = &storageFactoryRestOptionsFactory{Options: *s, StorageFactory: factory}
|
|
return nil
|
|
}
|
|
|
|
func (s *EtcdOptions) addEtcdHealthEndpoint(c *server.Config) {
|
|
c.HealthzChecks = append(c.HealthzChecks, healthz.NamedCheck("etcd", func(r *http.Request) error {
|
|
done, err := preflight.EtcdConnection{ServerList: s.StorageConfig.ServerList}.CheckEtcdServers()
|
|
if !done {
|
|
return fmt.Errorf("etcd failed")
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}))
|
|
}
|
|
|
|
type SimpleRestOptionsFactory struct {
|
|
Options EtcdOptions
|
|
}
|
|
|
|
func (f *SimpleRestOptionsFactory) GetRESTOptions(resource schema.GroupResource) (generic.RESTOptions, error) {
|
|
ret := generic.RESTOptions{
|
|
StorageConfig: &f.Options.StorageConfig,
|
|
Decorator: generic.UndecoratedStorage,
|
|
EnableGarbageCollection: f.Options.EnableGarbageCollection,
|
|
DeleteCollectionWorkers: f.Options.DeleteCollectionWorkers,
|
|
ResourcePrefix: resource.Group + "/" + resource.Resource,
|
|
}
|
|
if f.Options.EnableWatchCache {
|
|
ret.Decorator = genericregistry.StorageWithCacher(f.Options.DefaultWatchCacheSize)
|
|
}
|
|
return ret, nil
|
|
}
|
|
|
|
type storageFactoryRestOptionsFactory struct {
|
|
Options EtcdOptions
|
|
StorageFactory serverstorage.StorageFactory
|
|
}
|
|
|
|
func (f *storageFactoryRestOptionsFactory) GetRESTOptions(resource schema.GroupResource) (generic.RESTOptions, error) {
|
|
storageConfig, err := f.StorageFactory.NewConfig(resource)
|
|
if err != nil {
|
|
return generic.RESTOptions{}, fmt.Errorf("unable to find storage destination for %v, due to %v", resource, err.Error())
|
|
}
|
|
|
|
ret := generic.RESTOptions{
|
|
StorageConfig: storageConfig,
|
|
Decorator: generic.UndecoratedStorage,
|
|
DeleteCollectionWorkers: f.Options.DeleteCollectionWorkers,
|
|
EnableGarbageCollection: f.Options.EnableGarbageCollection,
|
|
ResourcePrefix: f.StorageFactory.ResourcePrefix(resource),
|
|
}
|
|
if f.Options.EnableWatchCache {
|
|
ret.Decorator = genericregistry.StorageWithCacher(f.Options.DefaultWatchCacheSize)
|
|
}
|
|
|
|
return ret, nil
|
|
}
|