Implement basic admission control framework

This commit is contained in:
derekwaynecarr
2015-01-06 11:44:43 -05:00
parent 3b5c3ec786
commit 520ae3ef27
19 changed files with 482 additions and 61 deletions

View File

@@ -0,0 +1,38 @@
/*
Copyright 2014 Google Inc. All rights reserved.
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 admission
import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
)
type admissionController struct {
client client.Interface
admissionHandler Interface
}
func NewAdmissionControl(client client.Interface, pluginNames []string, configFilePath string) AdmissionControl {
return &admissionController{
client: client,
admissionHandler: newInterface(pluginNames, configFilePath),
}
}
func (ac *admissionController) AdmissionControl(operation, kind, namespace string, object runtime.Object) (err error) {
return ac.admissionHandler.Admit(NewAttributesRecord(ac.client, object, namespace, kind, operation))
}

View File

@@ -0,0 +1,60 @@
/*
Copyright 2014 Google Inc. All rights reserved.
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 admission
import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
)
type attributesRecord struct {
client client.Interface
namespace string
kind string
operation string
object runtime.Object
}
func NewAttributesRecord(client client.Interface, object runtime.Object, namespace, kind, operation string) Attributes {
return &attributesRecord{
client: client,
namespace: namespace,
kind: kind,
operation: operation,
object: object,
}
}
func (record *attributesRecord) GetClient() client.Interface {
return record.client
}
func (record *attributesRecord) GetNamespace() string {
return record.namespace
}
func (record *attributesRecord) GetKind() string {
return record.kind
}
func (record *attributesRecord) GetOperation() string {
return record.operation
}
func (record *attributesRecord) GetObject() runtime.Object {
return record.object
}

45
pkg/admission/chain.go Normal file
View File

@@ -0,0 +1,45 @@
/*
Copyright 2014 Google Inc. All rights reserved.
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 admission
import ()
// chainAdmissionHandler is an instance of admission.Interface that performs admission control using a chain of admission handlers
type chainAdmissionHandler []Interface
// New returns an admission.Interface that will enforce admission control decisions
func newInterface(pluginNames []string, configFilePath string) Interface {
plugins := []Interface{}
for _, pluginName := range pluginNames {
plugin := InitPlugin(pluginName, configFilePath)
if plugin != nil {
plugins = append(plugins, plugin)
}
}
return chainAdmissionHandler(plugins)
}
// Admit performs an admission control check using a chain of handlers, and returns immediately on first error
func (admissionHandler chainAdmissionHandler) Admit(a Attributes) (err error) {
for _, handler := range admissionHandler {
err := handler.Admit(a)
if err != nil {
return err
}
}
return nil
}

View File

@@ -0,0 +1,43 @@
/*
Copyright 2014 Google Inc. All rights reserved.
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 admission
import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
)
// Attributes is an interface used by AdmissionController to get information about a request
// that is used to make an admission decision.
type Attributes interface {
GetClient() client.Interface
GetNamespace() string
GetKind() string
GetOperation() string
GetObject() runtime.Object
}
// Interface is an abstract, pluggable interface for Admission Control decisions.
type Interface interface {
// Admit makes an admission decision based on the request attributes
Admit(a Attributes) (err error)
}
// AdmissionControl is responsible for performing Admission control decisions
type AdmissionControl interface {
AdmissionControl(operation, kind, namespace string, object runtime.Object) (err error)
}

106
pkg/admission/plugins.go Normal file
View File

@@ -0,0 +1,106 @@
/*
Copyright 2014 Google Inc. All rights reserved.
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 admission
import (
"io"
"os"
"sync"
"github.com/golang/glog"
)
// Factory is a function that returns a Interface for admission decisions.
// The config parameter provides an io.Reader handler to the factory in
// order to load specific configurations. If no configuration is provided
// the parameter is nil.
type Factory func(config io.Reader) (Interface, error)
// All registered admission options.
var pluginsMutex sync.Mutex
var plugins = make(map[string]Factory)
// GetPlugins enumerates the
func GetPlugins() []string {
pluginsMutex.Lock()
defer pluginsMutex.Unlock()
keys := []string{}
for k := range plugins {
keys = append(keys, k)
}
return keys
}
// RegisterPlugin registers a plugin Factory by name. This
// is expected to happen during app startup.
func RegisterPlugin(name string, plugin Factory) {
pluginsMutex.Lock()
defer pluginsMutex.Unlock()
_, found := plugins[name]
if found {
glog.Fatalf("Admission plugin %q was registered twice", name)
}
glog.V(1).Infof("Registered admission plugin %q", name)
plugins[name] = plugin
}
// GetInterface creates an instance of the named plugin, or nil if
// the name is not known. The error return is only used if the named provider
// was known but failed to initialize. The config parameter specifies the
// io.Reader handler of the configuration file for the cloud provider, or nil
// for no configuation.
func GetPlugin(name string, config io.Reader) (Interface, error) {
pluginsMutex.Lock()
defer pluginsMutex.Unlock()
f, found := plugins[name]
if !found {
return nil, nil
}
return f(config)
}
// InitPlugin creates an instance of the named interface
func InitPlugin(name string, configFilePath string) Interface {
var config *os.File
if name == "" {
glog.Info("No admission plugin specified.")
return nil
}
if configFilePath != "" {
var err error
config, err = os.Open(configFilePath)
if err != nil {
glog.Fatalf("Couldn't open admission plugin configuration %s: %#v",
configFilePath, err)
}
defer config.Close()
}
plugin, err := GetPlugin(name, config)
if err != nil {
glog.Fatalf("Couldn't init admission plugin %q: %v", name, err)
}
if plugin == nil {
glog.Fatalf("Unknown admission plugin: %s", name)
}
return plugin
}