Revert "Add optional validation to kubecfg/kubectl."

This reverts commit acf6d82800.
pull/6/head
Joe Beda 2014-11-25 14:45:00 -08:00
parent f5f5542bb2
commit 6590c66dd4
9 changed files with 19 additions and 130 deletions

View File

@ -152,18 +152,12 @@ func readConfigData() []byte {
// readConfig reads and parses pod, replicationController, and service
// configuration files. If any errors log and exit non-zero.
func readConfig(storage string, c *client.Client) []byte {
serverCodec := c.RESTClient.Codec
func readConfig(storage string, serverCodec runtime.Codec) []byte {
if len(*config) == 0 {
glog.Fatal("Need config file (-c)")
}
dataInput := readConfigData()
err := kubecfg.ValidateObject(dataInput, c)
if err != nil {
glog.Fatalf("Error validating %v as an object for %v: %v\n", *config, storage, err)
}
data, err := parser.ToWireFormat(dataInput, storage, latest.Codec, serverCodec)
data, err := parser.ToWireFormat(readConfigData(), storage, latest.Codec, serverCodec)
if err != nil {
glog.Fatalf("Error parsing %v as an object for %v: %v\n", *config, storage, err)
@ -389,7 +383,7 @@ func executeAPIRequest(ctx api.Context, method string, c *client.Client) bool {
glog.Fatalf("usage: kubecfg [OPTIONS] %s <%s>/<id>", method, prettyWireStorage())
}
case "print":
data := readConfig(storage, c)
data := readConfig(storage, c.RESTClient.Codec)
obj, err := latest.Codec.Decode(data)
if err != nil {
glog.Fatalf("error setting resource version: %v", err)
@ -409,7 +403,7 @@ func executeAPIRequest(ctx api.Context, method string, c *client.Client) bool {
}
if setBody {
if len(version) > 0 {
data := readConfig(storage, c)
data := readConfig(storage, c.RESTClient.Codec)
obj, err := latest.Codec.Decode(data)
if err != nil {
glog.Fatalf("error setting resource version: %v", err)
@ -425,7 +419,7 @@ func executeAPIRequest(ctx api.Context, method string, c *client.Client) bool {
}
r.Body(data)
} else {
r.Body(readConfig(storage, c))
r.Body(readConfig(storage, c.RESTClient.Codec))
}
}
result := r.Do()

View File

@ -40,21 +40,12 @@ func NewInvalidTypeError(expected reflect.Kind, observed reflect.Kind, fieldName
return &InvalidTypeError{expected, observed, fieldName}
}
// Schema is an interface that knows how to validate an API object serialized to a byte array.
type Schema interface {
ValidateBytes(data []byte) error
}
type NullSchema struct{}
func (NullSchema) ValidateBytes(data []byte) error { return nil }
type SwaggerSchema struct {
type Schema struct {
api swagger.ApiDeclaration
}
func NewSwaggerSchemaFromBytes(data []byte) (Schema, error) {
schema := &SwaggerSchema{}
func NewSchemaFromBytes(data []byte) (*Schema, error) {
schema := &Schema{}
err := json.Unmarshal(data, &schema.api)
if err != nil {
return nil, err
@ -62,7 +53,7 @@ func NewSwaggerSchemaFromBytes(data []byte) (Schema, error) {
return schema, nil
}
func (s *SwaggerSchema) ValidateBytes(data []byte) error {
func (s *Schema) ValidateBytes(data []byte) error {
var obj interface{}
err := json.Unmarshal(data, &obj)
if err != nil {
@ -74,7 +65,7 @@ func (s *SwaggerSchema) ValidateBytes(data []byte) error {
return s.ValidateObject(obj, apiVersion, "", apiVersion+"."+kind)
}
func (s *SwaggerSchema) ValidateObject(obj interface{}, apiVersion, fieldName, typeName string) error {
func (s *Schema) ValidateObject(obj interface{}, apiVersion, fieldName, typeName string) error {
models := s.api.Models
// TODO: handle required fields here too.
model, ok := models[typeName]
@ -107,7 +98,7 @@ func (s *SwaggerSchema) ValidateObject(obj interface{}, apiVersion, fieldName, t
return nil
}
func (s *SwaggerSchema) validateField(value interface{}, apiVersion, fieldName, fieldType string, fieldDetails *swagger.ModelProperty) error {
func (s *Schema) validateField(value interface{}, apiVersion, fieldName, fieldType string, fieldDetails *swagger.ModelProperty) error {
if strings.HasPrefix(fieldType, apiVersion) {
return s.ValidateObject(value, apiVersion, fieldName, fieldType)
}

View File

@ -30,12 +30,12 @@ import (
fuzz "github.com/google/gofuzz"
)
func LoadSchemaForTest(file string) (Schema, error) {
func LoadSchemaForTest(file string) (*Schema, error) {
data, err := ioutil.ReadFile(file)
if err != nil {
return nil, err
}
return NewSwaggerSchemaFromBytes(data)
return NewSchemaFromBytes(data)
}
// TODO: this is cloned from serialization_test.go, refactor to somewhere common like util

View File

@ -1,51 +0,0 @@
/*
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 kubecfg
import (
"encoding/json"
"fmt"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
)
func ValidateObject(data []byte, c *client.Client) error {
var obj interface{}
err := json.Unmarshal(data, &obj)
if err != nil {
return err
}
apiVersion, found := obj.(map[string]interface{})["apiVersion"]
if !found {
return fmt.Errorf("couldn't find apiVersion in object")
}
schemaData, err := c.RESTClient.Get().
AbsPath("/swaggerapi/api").
Path(apiVersion.(string)).
Do().
Raw()
if err != nil {
return err
}
schema, err := validation.NewSwaggerSchemaFromBytes(schemaData)
if err != nil {
return err
}
return schema.ValidateBytes(data)
}

View File

@ -24,7 +24,6 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
@ -37,7 +36,6 @@ import (
type Factory struct {
Mapper meta.RESTMapper
Typer runtime.ObjectTyper
Validator func(*cobra.Command) (validation.Schema, error)
Client func(*cobra.Command, *meta.RESTMapping) (kubectl.RESTClient, error)
Describer func(*cobra.Command, *meta.RESTMapping) (kubectl.Describer, error)
Printer func(cmd *cobra.Command, mapping *meta.RESTMapping, noHeaders bool) (kubectl.ResourcePrinter, error)
@ -48,13 +46,6 @@ func NewFactory() *Factory {
return &Factory{
Mapper: latest.RESTMapper,
Typer: api.Scheme,
Validator: func(cmd *cobra.Command) (validation.Schema, error) {
if GetFlagBool(cmd, "validate") {
return &clientSwaggerSchema{getKubeClient(cmd), api.Scheme}, nil
} else {
return validation.NullSchema{}, nil
}
},
Client: func(cmd *cobra.Command, mapping *meta.RESTMapping) (kubectl.RESTClient, error) {
return getKubeClient(cmd), nil
},
@ -96,7 +87,6 @@ Find more information at https://github.com/GoogleCloudPlatform/kubernetes.`,
cmds.PersistentFlags().Bool("insecure-skip-tls-verify", false, "If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.")
cmds.PersistentFlags().String("ns-path", os.Getenv("HOME")+"/.kubernetes_ns", "Path to the namespace info file that holds the namespace context to use for CLI requests.")
cmds.PersistentFlags().StringP("namespace", "n", "", "If present, the namespace scope for this CLI request.")
cmds.PersistentFlags().Bool("validate", false, "If true, use a schema to validate the input before sending it")
cmds.AddCommand(NewCmdVersion(out))
cmds.AddCommand(NewCmdProxy(out))
@ -226,28 +216,3 @@ func getKubeClient(cmd *cobra.Command) *client.Client {
}
return c
}
type clientSwaggerSchema struct {
c *client.Client
t runtime.ObjectTyper
}
func (c *clientSwaggerSchema) ValidateBytes(data []byte) error {
version, _, err := c.t.DataVersionAndKind(data)
if err != nil {
return err
}
schemaData, err := c.c.RESTClient.Get().
AbsPath("/swaggerapi/api").
Path(version).
Do().
Raw()
if err != nil {
return err
}
schema, err := validation.NewSwaggerSchemaFromBytes(schemaData)
if err != nil {
return err
}
return schema.ValidateBytes(data)
}

View File

@ -43,9 +43,7 @@ Examples:
if len(filename) == 0 {
usageError(cmd, "Must specify filename to create")
}
schema, err := f.Validator(cmd)
checkErr(err)
mapping, namespace, name, data := ResourceFromFile(filename, f.Typer, f.Mapper, schema)
mapping, namespace, name, data := ResourceFromFile(filename, f.Typer, f.Mapper)
client, err := f.Client(cmd, mapping)
checkErr(err)

View File

@ -50,9 +50,7 @@ Examples:
<delete a pod with ID 1234-56-7890-234234-456456>`,
Run: func(cmd *cobra.Command, args []string) {
filename := GetFlagString(cmd, "filename")
schema, err := f.Validator(cmd)
checkErr(err)
mapping, namespace, name := ResourceFromArgsOrFile(cmd, args, filename, f.Typer, f.Mapper, schema)
mapping, namespace, name := ResourceFromArgsOrFile(cmd, args, filename, f.Typer, f.Mapper)
client, err := f.Client(cmd, mapping)
checkErr(err)

View File

@ -20,7 +20,6 @@ import (
"fmt"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
@ -30,7 +29,7 @@ import (
// ResourceFromArgsOrFile expects two arguments or a valid file with a given type, and extracts
// the fields necessary to uniquely locate a resource. Displays a usageError if that contract is
// not satisfied, or a generic error if any other problems occur.
func ResourceFromArgsOrFile(cmd *cobra.Command, args []string, filename string, typer runtime.ObjectTyper, mapper meta.RESTMapper, schema validation.Schema) (mapping *meta.RESTMapping, namespace, name string) {
func ResourceFromArgsOrFile(cmd *cobra.Command, args []string, filename string, typer runtime.ObjectTyper, mapper meta.RESTMapper) (mapping *meta.RESTMapping, namespace, name string) {
// If command line args are passed in, use those preferentially.
if len(args) > 0 && len(args) != 2 {
usageError(cmd, "If passing in command line parameters, must be resource and name")
@ -59,7 +58,7 @@ func ResourceFromArgsOrFile(cmd *cobra.Command, args []string, filename string,
usageError(cmd, "Must specify filename or command line params")
}
mapping, namespace, name, _ = ResourceFromFile(filename, typer, mapper, schema)
mapping, namespace, name, _ = ResourceFromFile(filename, typer, mapper)
if len(name) == 0 {
checkErr(fmt.Errorf("the resource in the provided file has no name (or ID) defined"))
}
@ -123,7 +122,7 @@ func ResourceOrTypeFromArgs(cmd *cobra.Command, args []string, mapper meta.RESTM
// ResourceFromFile retrieves the name and namespace from a valid file. If the file does not
// resolve to a known type an error is returned. The returned mapping can be used to determine
// the correct REST endpoint to modify this resource with.
func ResourceFromFile(filename string, typer runtime.ObjectTyper, mapper meta.RESTMapper, schema validation.Schema) (mapping *meta.RESTMapping, namespace, name string, data []byte) {
func ResourceFromFile(filename string, typer runtime.ObjectTyper, mapper meta.RESTMapper) (mapping *meta.RESTMapping, namespace, name string, data []byte) {
configData, err := ReadConfigData(filename)
checkErr(err)
data = configData
@ -136,9 +135,6 @@ func ResourceFromFile(filename string, typer runtime.ObjectTyper, mapper meta.RE
checkErr(fmt.Errorf("the resource in the provided file has no apiVersion defined"))
}
err = schema.ValidateBytes(data)
checkErr(err)
mapping, err = mapper.RESTMapping(version, kind)
checkErr(err)

View File

@ -43,9 +43,7 @@ Examples:
if len(filename) == 0 {
usageError(cmd, "Must specify filename to update")
}
schema, err := f.Validator(cmd)
checkErr(err)
mapping, namespace, name, data := ResourceFromFile(filename, f.Typer, f.Mapper, schema)
mapping, namespace, name, data := ResourceFromFile(filename, f.Typer, f.Mapper)
client, err := f.Client(cmd, mapping)
checkErr(err)