mirror of https://github.com/k3s-io/k3s
parent
f5f5542bb2
commit
6590c66dd4
|
@ -152,18 +152,12 @@ func readConfigData() []byte {
|
||||||
|
|
||||||
// readConfig reads and parses pod, replicationController, and service
|
// readConfig reads and parses pod, replicationController, and service
|
||||||
// configuration files. If any errors log and exit non-zero.
|
// configuration files. If any errors log and exit non-zero.
|
||||||
func readConfig(storage string, c *client.Client) []byte {
|
func readConfig(storage string, serverCodec runtime.Codec) []byte {
|
||||||
serverCodec := c.RESTClient.Codec
|
|
||||||
if len(*config) == 0 {
|
if len(*config) == 0 {
|
||||||
glog.Fatal("Need config file (-c)")
|
glog.Fatal("Need config file (-c)")
|
||||||
}
|
}
|
||||||
|
|
||||||
dataInput := readConfigData()
|
data, err := parser.ToWireFormat(readConfigData(), storage, latest.Codec, serverCodec)
|
||||||
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)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Error parsing %v as an object for %v: %v\n", *config, storage, err)
|
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())
|
glog.Fatalf("usage: kubecfg [OPTIONS] %s <%s>/<id>", method, prettyWireStorage())
|
||||||
}
|
}
|
||||||
case "print":
|
case "print":
|
||||||
data := readConfig(storage, c)
|
data := readConfig(storage, c.RESTClient.Codec)
|
||||||
obj, err := latest.Codec.Decode(data)
|
obj, err := latest.Codec.Decode(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("error setting resource version: %v", err)
|
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 setBody {
|
||||||
if len(version) > 0 {
|
if len(version) > 0 {
|
||||||
data := readConfig(storage, c)
|
data := readConfig(storage, c.RESTClient.Codec)
|
||||||
obj, err := latest.Codec.Decode(data)
|
obj, err := latest.Codec.Decode(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("error setting resource version: %v", err)
|
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)
|
r.Body(data)
|
||||||
} else {
|
} else {
|
||||||
r.Body(readConfig(storage, c))
|
r.Body(readConfig(storage, c.RESTClient.Codec))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result := r.Do()
|
result := r.Do()
|
||||||
|
|
|
@ -40,21 +40,12 @@ func NewInvalidTypeError(expected reflect.Kind, observed reflect.Kind, fieldName
|
||||||
return &InvalidTypeError{expected, observed, 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 struct {
|
||||||
type Schema interface {
|
|
||||||
ValidateBytes(data []byte) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type NullSchema struct{}
|
|
||||||
|
|
||||||
func (NullSchema) ValidateBytes(data []byte) error { return nil }
|
|
||||||
|
|
||||||
type SwaggerSchema struct {
|
|
||||||
api swagger.ApiDeclaration
|
api swagger.ApiDeclaration
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSwaggerSchemaFromBytes(data []byte) (Schema, error) {
|
func NewSchemaFromBytes(data []byte) (*Schema, error) {
|
||||||
schema := &SwaggerSchema{}
|
schema := &Schema{}
|
||||||
err := json.Unmarshal(data, &schema.api)
|
err := json.Unmarshal(data, &schema.api)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -62,7 +53,7 @@ func NewSwaggerSchemaFromBytes(data []byte) (Schema, error) {
|
||||||
return schema, nil
|
return schema, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SwaggerSchema) ValidateBytes(data []byte) error {
|
func (s *Schema) ValidateBytes(data []byte) error {
|
||||||
var obj interface{}
|
var obj interface{}
|
||||||
err := json.Unmarshal(data, &obj)
|
err := json.Unmarshal(data, &obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -74,7 +65,7 @@ func (s *SwaggerSchema) ValidateBytes(data []byte) error {
|
||||||
return s.ValidateObject(obj, apiVersion, "", apiVersion+"."+kind)
|
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
|
models := s.api.Models
|
||||||
// TODO: handle required fields here too.
|
// TODO: handle required fields here too.
|
||||||
model, ok := models[typeName]
|
model, ok := models[typeName]
|
||||||
|
@ -107,7 +98,7 @@ func (s *SwaggerSchema) ValidateObject(obj interface{}, apiVersion, fieldName, t
|
||||||
return nil
|
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) {
|
if strings.HasPrefix(fieldType, apiVersion) {
|
||||||
return s.ValidateObject(value, apiVersion, fieldName, fieldType)
|
return s.ValidateObject(value, apiVersion, fieldName, fieldType)
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,12 +30,12 @@ import (
|
||||||
fuzz "github.com/google/gofuzz"
|
fuzz "github.com/google/gofuzz"
|
||||||
)
|
)
|
||||||
|
|
||||||
func LoadSchemaForTest(file string) (Schema, error) {
|
func LoadSchemaForTest(file string) (*Schema, error) {
|
||||||
data, err := ioutil.ReadFile(file)
|
data, err := ioutil.ReadFile(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return NewSwaggerSchemaFromBytes(data)
|
return NewSchemaFromBytes(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this is cloned from serialization_test.go, refactor to somewhere common like util
|
// TODO: this is cloned from serialization_test.go, refactor to somewhere common like util
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
|
|
@ -24,7 +24,6 @@ import (
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
|
"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/client"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||||
|
@ -37,7 +36,6 @@ import (
|
||||||
type Factory struct {
|
type Factory struct {
|
||||||
Mapper meta.RESTMapper
|
Mapper meta.RESTMapper
|
||||||
Typer runtime.ObjectTyper
|
Typer runtime.ObjectTyper
|
||||||
Validator func(*cobra.Command) (validation.Schema, error)
|
|
||||||
Client func(*cobra.Command, *meta.RESTMapping) (kubectl.RESTClient, error)
|
Client func(*cobra.Command, *meta.RESTMapping) (kubectl.RESTClient, error)
|
||||||
Describer func(*cobra.Command, *meta.RESTMapping) (kubectl.Describer, error)
|
Describer func(*cobra.Command, *meta.RESTMapping) (kubectl.Describer, error)
|
||||||
Printer func(cmd *cobra.Command, mapping *meta.RESTMapping, noHeaders bool) (kubectl.ResourcePrinter, error)
|
Printer func(cmd *cobra.Command, mapping *meta.RESTMapping, noHeaders bool) (kubectl.ResourcePrinter, error)
|
||||||
|
@ -48,13 +46,6 @@ func NewFactory() *Factory {
|
||||||
return &Factory{
|
return &Factory{
|
||||||
Mapper: latest.RESTMapper,
|
Mapper: latest.RESTMapper,
|
||||||
Typer: api.Scheme,
|
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) {
|
Client: func(cmd *cobra.Command, mapping *meta.RESTMapping) (kubectl.RESTClient, error) {
|
||||||
return getKubeClient(cmd), nil
|
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().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().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().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(NewCmdVersion(out))
|
||||||
cmds.AddCommand(NewCmdProxy(out))
|
cmds.AddCommand(NewCmdProxy(out))
|
||||||
|
@ -226,28 +216,3 @@ func getKubeClient(cmd *cobra.Command) *client.Client {
|
||||||
}
|
}
|
||||||
return c
|
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)
|
|
||||||
}
|
|
||||||
|
|
|
@ -43,9 +43,7 @@ Examples:
|
||||||
if len(filename) == 0 {
|
if len(filename) == 0 {
|
||||||
usageError(cmd, "Must specify filename to create")
|
usageError(cmd, "Must specify filename to create")
|
||||||
}
|
}
|
||||||
schema, err := f.Validator(cmd)
|
mapping, namespace, name, data := ResourceFromFile(filename, f.Typer, f.Mapper)
|
||||||
checkErr(err)
|
|
||||||
mapping, namespace, name, data := ResourceFromFile(filename, f.Typer, f.Mapper, schema)
|
|
||||||
client, err := f.Client(cmd, mapping)
|
client, err := f.Client(cmd, mapping)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
|
||||||
|
|
|
@ -50,9 +50,7 @@ Examples:
|
||||||
<delete a pod with ID 1234-56-7890-234234-456456>`,
|
<delete a pod with ID 1234-56-7890-234234-456456>`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
filename := GetFlagString(cmd, "filename")
|
filename := GetFlagString(cmd, "filename")
|
||||||
schema, err := f.Validator(cmd)
|
mapping, namespace, name := ResourceFromArgsOrFile(cmd, args, filename, f.Typer, f.Mapper)
|
||||||
checkErr(err)
|
|
||||||
mapping, namespace, name := ResourceFromArgsOrFile(cmd, args, filename, f.Typer, f.Mapper, schema)
|
|
||||||
client, err := f.Client(cmd, mapping)
|
client, err := f.Client(cmd, mapping)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
|
"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/kubectl"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
"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
|
// 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
|
// 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.
|
// 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 command line args are passed in, use those preferentially.
|
||||||
if len(args) > 0 && len(args) != 2 {
|
if len(args) > 0 && len(args) != 2 {
|
||||||
usageError(cmd, "If passing in command line parameters, must be resource and name")
|
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")
|
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 {
|
if len(name) == 0 {
|
||||||
checkErr(fmt.Errorf("the resource in the provided file has no name (or ID) defined"))
|
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
|
// 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
|
// 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.
|
// 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)
|
configData, err := ReadConfigData(filename)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
data = configData
|
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"))
|
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)
|
mapping, err = mapper.RESTMapping(version, kind)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
|
||||||
|
|
|
@ -43,9 +43,7 @@ Examples:
|
||||||
if len(filename) == 0 {
|
if len(filename) == 0 {
|
||||||
usageError(cmd, "Must specify filename to update")
|
usageError(cmd, "Must specify filename to update")
|
||||||
}
|
}
|
||||||
schema, err := f.Validator(cmd)
|
mapping, namespace, name, data := ResourceFromFile(filename, f.Typer, f.Mapper)
|
||||||
checkErr(err)
|
|
||||||
mapping, namespace, name, data := ResourceFromFile(filename, f.Typer, f.Mapper, schema)
|
|
||||||
client, err := f.Client(cmd, mapping)
|
client, err := f.Client(cmd, mapping)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue