Commit 4c5a7e59 authored by bgrant0607's avatar bgrant0607

Merge pull request #2492 from brendandburns/valid

Add a swagger schema validator, for validating client side json files.
parents 16f57883 6c53d3b4
/*
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 validation
import (
"encoding/json"
"fmt"
"reflect"
"strings"
"github.com/emicklei/go-restful/swagger"
"github.com/golang/glog"
)
type InvalidTypeError struct {
ExpectedKind reflect.Kind
ObservedKind reflect.Kind
FieldName string
}
func (i *InvalidTypeError) Error() string {
return fmt.Sprintf("expected type %s, for field %s, got %s", i.ExpectedKind.String(), i.FieldName, i.ObservedKind.String())
}
func NewInvalidTypeError(expected reflect.Kind, observed reflect.Kind, fieldName string) error {
return &InvalidTypeError{expected, observed, fieldName}
}
type Schema struct {
api swagger.ApiDeclaration
}
func NewSchemaFromBytes(data []byte) (*Schema, error) {
schema := &Schema{}
err := json.Unmarshal(data, &schema.api)
if err != nil {
return nil, err
}
return schema, nil
}
func (s *Schema) ValidateBytes(data []byte) error {
var obj interface{}
err := json.Unmarshal(data, &obj)
if err != nil {
return err
}
fields := obj.(map[string]interface{})
apiVersion := fields["apiVersion"].(string)
kind := fields["kind"].(string)
return s.ValidateObject(obj, apiVersion, "", apiVersion+"."+kind)
}
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]
if !ok {
glog.V(2).Infof("couldn't find type: %s, skipping validation", typeName)
return nil
}
properties := model.Properties
fields := obj.(map[string]interface{})
if len(fieldName) > 0 {
fieldName = fieldName + "."
}
for key, value := range fields {
details, ok := properties[key]
if !ok {
glog.V(2).Infof("couldn't find properties for %s, skipping", key)
continue
}
fieldType := *details.Type
if value == nil {
glog.V(2).Infof("Skipping nil field: %s", key)
continue
}
err := s.validateField(value, apiVersion, fieldName+key, fieldType, &details)
if err != nil {
glog.Errorf("Validation failed for: %s, %v", key, value)
return err
}
}
return nil
}
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)
}
switch fieldType {
case "string":
// Be loose about what we accept for 'string' since we use IntOrString in a couple of places
_, isString := value.(string)
_, isNumber := value.(float64)
if !isString && !isNumber {
return NewInvalidTypeError(reflect.String, reflect.TypeOf(value).Kind(), fieldName)
}
case "array":
arr, ok := value.([]interface{})
if !ok {
return NewInvalidTypeError(reflect.Array, reflect.TypeOf(value).Kind(), fieldName)
}
arrType := *fieldDetails.Items[0].Ref
for ix := range arr {
err := s.validateField(arr[ix], apiVersion, fmt.Sprintf("%s[%d]", fieldName, ix), arrType, nil)
if err != nil {
return err
}
}
case "uint64":
case "integer":
if _, ok := value.(float64); !ok {
return NewInvalidTypeError(reflect.Int, reflect.TypeOf(value).Kind(), fieldName)
}
case "float64":
if _, ok := value.(float64); !ok {
return NewInvalidTypeError(reflect.Float64, reflect.TypeOf(value).Kind(), fieldName)
}
case "boolean":
if _, ok := value.(bool); !ok {
return NewInvalidTypeError(reflect.Bool, reflect.TypeOf(value).Kind(), fieldName)
}
default:
return fmt.Errorf("unexpected type: %v", fieldType)
}
return nil
}
/*
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 validation
import (
"io/ioutil"
"strconv"
"testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
docker "github.com/fsouza/go-dockerclient"
fuzz "github.com/google/gofuzz"
)
func LoadSchemaForTest(file string) (*Schema, error) {
data, err := ioutil.ReadFile(file)
if err != nil {
return nil, err
}
return NewSchemaFromBytes(data)
}
// TODO: this is cloned from serialization_test.go, refactor to somewhere common like util
// apiObjectFuzzer can randomly populate api objects.
var apiObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 1).Funcs(
func(j *runtime.PluginBase, c fuzz.Continue) {
// Do nothing; this struct has only a Kind field and it must stay blank in memory.
},
func(j *runtime.TypeMeta, c fuzz.Continue) {
// We have to customize the randomization of TypeMetas because their
// APIVersion and Kind must remain blank in memory.
j.APIVersion = ""
j.Kind = ""
j.Name = c.RandString()
// TODO: Fix JSON/YAML packages and/or write custom encoding
// for uint64's. Somehow the LS *byte* of this is lost, but
// only when all 8 bytes are set.
j.ResourceVersion = strconv.FormatUint(c.RandUint64()>>8, 10)
j.SelfLink = c.RandString()
var sec, nsec int64
c.Fuzz(&sec)
c.Fuzz(&nsec)
j.CreationTimestamp = util.Unix(sec, nsec).Rfc3339Copy()
},
func(j *api.TypeMeta, c fuzz.Continue) {
// We have to customize the randomization of TypeMetas because their
// APIVersion and Kind must remain blank in memory.
j.APIVersion = ""
j.Kind = ""
},
func(j *api.ObjectMeta, c fuzz.Continue) {
j.Name = c.RandString()
// TODO: Fix JSON/YAML packages and/or write custom encoding
// for uint64's. Somehow the LS *byte* of this is lost, but
// only when all 8 bytes are set.
j.ResourceVersion = strconv.FormatUint(c.RandUint64()>>8, 10)
j.SelfLink = c.RandString()
var sec, nsec int64
c.Fuzz(&sec)
c.Fuzz(&nsec)
j.CreationTimestamp = util.Unix(sec, nsec).Rfc3339Copy()
},
func(j *api.ListMeta, c fuzz.Continue) {
// TODO: Fix JSON/YAML packages and/or write custom encoding
// for uint64's. Somehow the LS *byte* of this is lost, but
// only when all 8 bytes are set.
j.ResourceVersion = strconv.FormatUint(c.RandUint64()>>8, 10)
j.SelfLink = c.RandString()
},
func(j *api.PodCondition, c fuzz.Continue) {
statuses := []api.PodCondition{api.PodPending, api.PodRunning, api.PodFailed}
*j = statuses[c.Rand.Intn(len(statuses))]
},
func(j *api.ReplicationControllerSpec, c fuzz.Continue) {
// TemplateRef must be nil for round trip
c.Fuzz(&j.Template)
if j.Template == nil {
// TODO: v1beta1/2 can't round trip a nil template correctly, fix by having v1beta1/2
// conversion compare converted object to nil via DeepEqual
j.Template = &api.PodTemplateSpec{}
}
j.Template.ObjectMeta = api.ObjectMeta{Labels: j.Template.ObjectMeta.Labels}
j.Template.Spec.NodeSelector = nil
c.Fuzz(&j.Selector)
j.Replicas = int(c.RandUint64())
},
func(j *api.ReplicationControllerStatus, c fuzz.Continue) {
// only replicas round trips
j.Replicas = int(c.RandUint64())
},
func(intstr *util.IntOrString, c fuzz.Continue) {
// util.IntOrString will panic if its kind is set wrong.
if c.RandBool() {
intstr.Kind = util.IntstrInt
intstr.IntVal = int(c.RandUint64())
intstr.StrVal = ""
} else {
intstr.Kind = util.IntstrString
intstr.IntVal = 0
intstr.StrVal = c.RandString()
}
},
func(u64 *uint64, c fuzz.Continue) {
// TODO: uint64's are NOT handled right.
*u64 = c.RandUint64() >> 8
},
func(pb map[docker.Port][]docker.PortBinding, c fuzz.Continue) {
// This is necessary because keys with nil values get omitted.
// TODO: Is this a bug?
pb[docker.Port(c.RandString())] = []docker.PortBinding{
{c.RandString(), c.RandString()},
{c.RandString(), c.RandString()},
}
},
func(pm map[string]docker.PortMapping, c fuzz.Continue) {
// This is necessary because keys with nil values get omitted.
// TODO: Is this a bug?
pm[c.RandString()] = docker.PortMapping{
c.RandString(): c.RandString(),
}
},
)
func TestLoad(t *testing.T) {
_, err := LoadSchemaForTest("v1beta1-swagger.json")
if err != nil {
t.Errorf("Failed to load: %v", err)
}
}
func TestValidateOk(t *testing.T) {
schema, err := LoadSchemaForTest("v1beta1-swagger.json")
if err != nil {
t.Errorf("Failed to load: %v", err)
}
tests := []struct {
obj runtime.Object
typeName string
}{
{obj: &api.Pod{}},
{obj: &api.Service{}},
{obj: &api.ReplicationController{}},
}
for i := 0; i < 5; i++ {
for _, test := range tests {
testObj := test.obj
apiObjectFuzzer.Fuzz(testObj)
data, err := v1beta1.Codec.Encode(testObj)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
err = schema.ValidateBytes(data)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
}
}
}
var invalidPod = `{
"id": "name",
"kind": "Pod",
"apiVersion": "v1beta1",
"desiredState": {
"manifest": {
"version": "v1beta1",
"id": "redis-master",
"containers": [{
"name": "master",
"image": "dockerfile/redis",
"command": "this is a bad command",
}]
}
},
"labels": {
"name": "redis-master"
}
}
`
var invalidPod2 = `{
"apiVersion": "v1beta1",
"kind": "Pod",
"id": "apache-php",
"desiredState": {
"manifest": {
"version": "v1beta1",
"id": "apache-php",
"containers": [
{
"name": "apache-php",
"image": "php:5.6.2-apache",
"ports": [{ "name": "apache", "containerPort": 80, "hostPort":"13380", "protocol":"TCP" }],
"volumeMounts": [{"name": "shared-disk","mountPath": "/var/www/html", "readOnly": false}]
}
]
}
},
"labels": { "name": "apache-php" },
"restartPolicy": {"always": {}},
"volumes": [
"name": "shared-disk",
"source": {
"GCEPersistentDisk": {
"path": "shared-disk"
}
}
]
}
`
var invalidPod3 = `{
"apiVersion": "v1beta1",
"kind": "Pod",
"id": "apache-php",
"desiredState": {
"manifest": {
"version": "v1beta1",
"id": "apache-php",
"containers": [
{
"name": "apache-php",
"image": "php:5.6.2-apache",
"ports": [{ "name": "apache", "containerPort": 80, "hostPort":"13380", "protocol":"TCP" }],
"volumeMounts": [{"name": "shared-disk","mountPath": "/var/www/html", "readOnly": false}]
}
]
}
},
"labels": { "name": "apache-php" },
"restartPolicy": {"always": {}},
"volumes": [
{
"name": "shared-disk",
"source": {
"GCEPersistentDisk": {
"path": "shared-disk"
}
}
}
]
}
`
func TestInvalid(t *testing.T) {
schema, err := LoadSchemaForTest("v1beta1-swagger.json")
if err != nil {
t.Errorf("Failed to load: %v", err)
}
tests := []string{invalidPod, invalidPod2}
for _, test := range tests {
err = schema.ValidateBytes([]byte(test))
if err == nil {
t.Errorf("unexpected non-error\n%s", test)
}
}
}
{
"swaggerVersion": "1.2",
"apiVersion": "",
"basePath": "http://127.0.0.1:8080",
"resourcePath": "/api/v1beta1",
"apis": [
{
"path": "/api/v1beta1/bindings",
"description": "API at /api, version v1beta1",
"operations": [
{
"type": "void",
"method": "POST",
"summary": "create a Binding",
"nickname": "createBinding",
"parameters": [
{
"type": "v1beta1.Binding",
"paramType": "body",
"name": "v1beta1.Binding",
"description": "",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
}
]
},
{
"path": "/api/v1beta1/replicationControllers/{name}",
"description": "API at /api, version v1beta1",
"operations": [
{
"type": "v1beta1.ReplicationController",
"method": "GET",
"summary": "read the specified ReplicationController",
"nickname": "readReplicationController",
"parameters": [
{
"type": "string",
"paramType": "path",
"name": "name",
"description": "name of the ReplicationController",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
},
{
"type": "void",
"method": "PUT",
"summary": "update the specified ReplicationController",
"nickname": "updateReplicationController",
"parameters": [
{
"type": "string",
"paramType": "path",
"name": "name",
"description": "name of the ReplicationController",
"required": true,
"allowMultiple": false
},
{
"type": "v1beta1.ReplicationController",
"paramType": "body",
"name": "v1beta1.ReplicationController",
"description": "",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
},
{
"type": "void",
"method": "DELETE",
"summary": "delete the specified ReplicationController",
"nickname": "deleteReplicationController",
"parameters": [
{
"type": "string",
"paramType": "path",
"name": "name",
"description": "name of the ReplicationController",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
}
]
},
{
"path": "/api/v1beta1/services/{name}",
"description": "API at /api, version v1beta1",
"operations": [
{
"type": "v1beta1.Service",
"method": "GET",
"summary": "read the specified Service",
"nickname": "readService",
"parameters": [
{
"type": "string",
"paramType": "path",
"name": "name",
"description": "name of the Service",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
},
{
"type": "void",
"method": "PUT",
"summary": "update the specified Service",
"nickname": "updateService",
"parameters": [
{
"type": "string",
"paramType": "path",
"name": "name",
"description": "name of the Service",
"required": true,
"allowMultiple": false
},
{
"type": "v1beta1.Service",
"paramType": "body",
"name": "v1beta1.Service",
"description": "",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
},
{
"type": "void",
"method": "DELETE",
"summary": "delete the specified Service",
"nickname": "deleteService",
"parameters": [
{
"type": "string",
"paramType": "path",
"name": "name",
"description": "name of the Service",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
}
]
},
{
"path": "/api/v1beta1/endpoints",
"description": "API at /api, version v1beta1",
"operations": [
{
"type": "void",
"method": "POST",
"summary": "create a Endpoints",
"nickname": "createEndpoints",
"parameters": [
{
"type": "v1beta1.Endpoints",
"paramType": "body",
"name": "v1beta1.Endpoints",
"description": "",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
},
{
"type": "void",
"method": "GET",
"summary": "list objects of kind Endpoints",
"nickname": "listEndpoints",
"parameters": [],
"responseMessages": [
{
"code": 200,
"message": "OK",
"responseModel": "v1beta1.EndpointsList"
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
}
]
},
{
"path": "/api/v1beta1/events/{name}",
"description": "API at /api, version v1beta1",
"operations": [
{
"type": "v1beta1.Event",
"method": "GET",
"summary": "read the specified Event",
"nickname": "readEvent",
"parameters": [
{
"type": "string",
"paramType": "path",
"name": "name",
"description": "name of the Event",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
},
{
"type": "void",
"method": "PUT",
"summary": "update the specified Event",
"nickname": "updateEvent",
"parameters": [
{
"type": "string",
"paramType": "path",
"name": "name",
"description": "name of the Event",
"required": true,
"allowMultiple": false
},
{
"type": "v1beta1.Event",
"paramType": "body",
"name": "v1beta1.Event",
"description": "",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
},
{
"type": "void",
"method": "DELETE",
"summary": "delete the specified Event",
"nickname": "deleteEvent",
"parameters": [
{
"type": "string",
"paramType": "path",
"name": "name",
"description": "name of the Event",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
}
]
},
{
"path": "/api/v1beta1/events",
"description": "API at /api, version v1beta1",
"operations": [
{
"type": "void",
"method": "POST",
"summary": "create a Event",
"nickname": "createEvent",
"parameters": [
{
"type": "v1beta1.Event",
"paramType": "body",
"name": "v1beta1.Event",
"description": "",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
},
{
"type": "void",
"method": "GET",
"summary": "list objects of kind Event",
"nickname": "listEvent",
"parameters": [],
"responseMessages": [
{
"code": 200,
"message": "OK",
"responseModel": "v1beta1.EventList"
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
}
]
},
{
"path": "/api/v1beta1/services",
"description": "API at /api, version v1beta1",
"operations": [
{
"type": "void",
"method": "POST",
"summary": "create a Service",
"nickname": "createService",
"parameters": [
{
"type": "v1beta1.Service",
"paramType": "body",
"name": "v1beta1.Service",
"description": "",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
},
{
"type": "void",
"method": "GET",
"summary": "list objects of kind Service",
"nickname": "listService",
"parameters": [],
"responseMessages": [
{
"code": 200,
"message": "OK",
"responseModel": "v1beta1.ServiceList"
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
}
]
},
{
"path": "/api/v1beta1/minions",
"description": "API at /api, version v1beta1",
"operations": [
{
"type": "void",
"method": "POST",
"summary": "create a Minion",
"nickname": "createMinion",
"parameters": [
{
"type": "v1beta1.Minion",
"paramType": "body",
"name": "v1beta1.Minion",
"description": "",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
},
{
"type": "void",
"method": "GET",
"summary": "list objects of kind Minion",
"nickname": "listMinion",
"parameters": [],
"responseMessages": [
{
"code": 200,
"message": "OK",
"responseModel": "v1beta1.MinionList"
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
}
]
},
{
"path": "/api/v1beta1/minions/{name}",
"description": "API at /api, version v1beta1",
"operations": [
{
"type": "v1beta1.Minion",
"method": "GET",
"summary": "read the specified Minion",
"nickname": "readMinion",
"parameters": [
{
"type": "string",
"paramType": "path",
"name": "name",
"description": "name of the Minion",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
},
{
"type": "void",
"method": "PUT",
"summary": "update the specified Minion",
"nickname": "updateMinion",
"parameters": [
{
"type": "string",
"paramType": "path",
"name": "name",
"description": "name of the Minion",
"required": true,
"allowMultiple": false
},
{
"type": "v1beta1.Minion",
"paramType": "body",
"name": "v1beta1.Minion",
"description": "",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
},
{
"type": "void",
"method": "DELETE",
"summary": "delete the specified Minion",
"nickname": "deleteMinion",
"parameters": [
{
"type": "string",
"paramType": "path",
"name": "name",
"description": "name of the Minion",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
}
]
},
{
"path": "/api/v1beta1/pods/{name}",
"description": "API at /api, version v1beta1",
"operations": [
{
"type": "v1beta1.Pod",
"method": "GET",
"summary": "read the specified Pod",
"nickname": "readPod",
"parameters": [
{
"type": "string",
"paramType": "path",
"name": "name",
"description": "name of the Pod",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
},
{
"type": "void",
"method": "PUT",
"summary": "update the specified Pod",
"nickname": "updatePod",
"parameters": [
{
"type": "string",
"paramType": "path",
"name": "name",
"description": "name of the Pod",
"required": true,
"allowMultiple": false
},
{
"type": "v1beta1.Pod",
"paramType": "body",
"name": "v1beta1.Pod",
"description": "",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
},
{
"type": "void",
"method": "DELETE",
"summary": "delete the specified Pod",
"nickname": "deletePod",
"parameters": [
{
"type": "string",
"paramType": "path",
"name": "name",
"description": "name of the Pod",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
}
]
},
{
"path": "/api/v1beta1/replicationControllers",
"description": "API at /api, version v1beta1",
"operations": [
{
"type": "void",
"method": "POST",
"summary": "create a ReplicationController",
"nickname": "createReplicationController",
"parameters": [
{
"type": "v1beta1.ReplicationController",
"paramType": "body",
"name": "v1beta1.ReplicationController",
"description": "",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
},
{
"type": "void",
"method": "GET",
"summary": "list objects of kind ReplicationController",
"nickname": "listReplicationController",
"parameters": [],
"responseMessages": [
{
"code": 200,
"message": "OK",
"responseModel": "v1beta1.ReplicationControllerList"
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
}
]
},
{
"path": "/api/v1beta1/endpoints/{name}",
"description": "API at /api, version v1beta1",
"operations": [
{
"type": "v1beta1.Endpoints",
"method": "GET",
"summary": "read the specified Endpoints",
"nickname": "readEndpoints",
"parameters": [
{
"type": "string",
"paramType": "path",
"name": "name",
"description": "name of the Endpoints",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
},
{
"type": "void",
"method": "PUT",
"summary": "update the specified Endpoints",
"nickname": "updateEndpoints",
"parameters": [
{
"type": "string",
"paramType": "path",
"name": "name",
"description": "name of the Endpoints",
"required": true,
"allowMultiple": false
},
{
"type": "v1beta1.Endpoints",
"paramType": "body",
"name": "v1beta1.Endpoints",
"description": "",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
},
{
"type": "void",
"method": "DELETE",
"summary": "delete the specified Endpoints",
"nickname": "deleteEndpoints",
"parameters": [
{
"type": "string",
"paramType": "path",
"name": "name",
"description": "name of the Endpoints",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
}
]
},
{
"path": "/api/v1beta1/bindings/{name}",
"description": "API at /api, version v1beta1",
"operations": [
{
"type": "v1beta1.Binding",
"method": "GET",
"summary": "read the specified Binding",
"nickname": "readBinding",
"parameters": [
{
"type": "string",
"paramType": "path",
"name": "name",
"description": "name of the Binding",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
},
{
"type": "void",
"method": "PUT",
"summary": "update the specified Binding",
"nickname": "updateBinding",
"parameters": [
{
"type": "string",
"paramType": "path",
"name": "name",
"description": "name of the Binding",
"required": true,
"allowMultiple": false
},
{
"type": "v1beta1.Binding",
"paramType": "body",
"name": "v1beta1.Binding",
"description": "",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
},
{
"type": "void",
"method": "DELETE",
"summary": "delete the specified Binding",
"nickname": "deleteBinding",
"parameters": [
{
"type": "string",
"paramType": "path",
"name": "name",
"description": "name of the Binding",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
}
]
},
{
"path": "/api/v1beta1/pods",
"description": "API at /api, version v1beta1",
"operations": [
{
"type": "void",
"method": "POST",
"summary": "create a Pod",
"nickname": "createPod",
"parameters": [
{
"type": "v1beta1.Pod",
"paramType": "body",
"name": "v1beta1.Pod",
"description": "",
"required": true,
"allowMultiple": false
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
},
{
"type": "void",
"method": "GET",
"summary": "list objects of kind Pod",
"nickname": "listPod",
"parameters": [],
"responseMessages": [
{
"code": 200,
"message": "OK",
"responseModel": "v1beta1.PodList"
}
],
"produces": [
"application/json"
],
"consumes": [
"*/*"
]
}
]
}
],
"models": {
"v1beta1.Binding": {
"id": "v1beta1.Binding",
"required": [
"annotations",
"kind",
"id",
"creationTimestamp",
"selfLink",
"namespace",
"uid",
"resourceVersion",
"apiVersion",
"podID",
"host"
],
"properties": {
"annotations": {
"type": "v1beta1.TypeMeta.annotations"
},
"apiVersion": {
"type": "string"
},
"creationTimestamp": {
"type": "string"
},
"host": {
"type": "string"
},
"id": {
"type": "string"
},
"kind": {
"type": "string"
},
"namespace": {
"type": "string"
},
"podID": {
"type": "string"
},
"resourceVersion": {
"type": "uint64"
},
"selfLink": {
"type": "string"
},
"uid": {
"type": "string"
}
}
},
"v1beta1.Container": {
"id": "v1beta1.Container",
"required": [
"name",
"image",
"imagePullPolicy"
],
"properties": {
"command": {
"type": "array",
"items": [
{
"$ref": "string"
}
]
},
"cpu": {
"type": "integer",
"format": "int32"
},
"env": {
"type": "array",
"items": [
{
"$ref": "v1beta1.EnvVar"
}
]
},
"image": {
"type": "string"
},
"imagePullPolicy": {
"type": "v1beta1.PullPolicy"
},
"lifecycle": {
"type": "v1beta1.Lifecycle"
},
"livenessProbe": {
"type": "v1beta1.LivenessProbe"
},
"memory": {
"type": "integer",
"format": "int32"
},
"name": {
"type": "string"
},
"ports": {
"type": "array",
"items": [
{
"$ref": "v1beta1.Port"
}
]
},
"privileged": {
"type": "boolean"
},
"terminationMessagePath": {
"type": "string"
},
"volumeMounts": {
"type": "array",
"items": [
{
"$ref": "v1beta1.VolumeMount"
}
]
},
"workingDir": {
"type": "string"
}
}
},
"v1beta1.ContainerManifest": {
"id": "v1beta1.ContainerManifest",
"required": [
"version",
"id",
"volumes",
"containers"
],
"properties": {
"containers": {
"type": "array",
"items": [
{
"$ref": "v1beta1.Container"
}
]
},
"id": {
"type": "string"
},
"restartPolicy": {
"type": "v1beta1.RestartPolicy"
},
"uuid": {
"type": "string"
},
"version": {
"type": "string"
},
"volumes": {
"type": "array",
"items": [
{
"$ref": "v1beta1.Volume"
}
]
}
}
},
"v1beta1.EmptyDir": {
"id": "v1beta1.EmptyDir",
"properties": {}
},
"v1beta1.Endpoints": {
"id": "v1beta1.Endpoints",
"required": [
"creationTimestamp",
"selfLink",
"namespace",
"kind",
"id",
"uid",
"resourceVersion",
"apiVersion",
"annotations"
],
"properties": {
"annotations": {
"type": "v1beta1.TypeMeta.annotations"
},
"apiVersion": {
"type": "string"
},
"creationTimestamp": {
"type": "string"
},
"endpoints": {
"type": "array",
"items": [
{
"$ref": "string"
}
]
},
"id": {
"type": "string"
},
"kind": {
"type": "string"
},
"namespace": {
"type": "string"
},
"resourceVersion": {
"type": "uint64"
},
"selfLink": {
"type": "string"
},
"uid": {
"type": "string"
}
}
},
"v1beta1.EndpointsList": {
"id": "v1beta1.EndpointsList",
"required": [
"creationTimestamp",
"selfLink",
"resourceVersion",
"apiVersion",
"namespace",
"kind",
"id",
"uid",
"annotations",
"items"
],
"properties": {
"annotations": {
"type": "v1beta1.TypeMeta.annotations"
},
"apiVersion": {
"type": "string"
},
"creationTimestamp": {
"type": "string"
},
"id": {
"type": "string"
},
"items": {
"type": "array",
"items": [
{
"$ref": "v1beta1.Endpoints"
}
]
},
"kind": {
"type": "string"
},
"namespace": {
"type": "string"
},
"resourceVersion": {
"type": "uint64"
},
"selfLink": {
"type": "string"
},
"uid": {
"type": "string"
}
}
},
"v1beta1.EnvVar": {
"id": "v1beta1.EnvVar",
"required": [
"name"
],
"properties": {
"key": {
"type": "string"
},
"name": {
"type": "string"
},
"value": {
"type": "string"
}
}
},
"v1beta1.Event": {
"id": "v1beta1.Event",
"required": [
"id",
"uid",
"resourceVersion",
"namespace",
"kind",
"creationTimestamp",
"selfLink",
"apiVersion",
"annotations"
],
"properties": {
"annotations": {
"type": "v1beta1.TypeMeta.annotations"
},
"apiVersion": {
"type": "string"
},
"creationTimestamp": {
"type": "string"
},
"id": {
"type": "string"
},
"involvedObject": {
"type": "v1beta1.ObjectReference"
},
"kind": {
"type": "string"
},
"message": {
"type": "string"
},
"namespace": {
"type": "string"
},
"reason": {
"type": "string"
},
"resourceVersion": {
"type": "uint64"
},
"selfLink": {
"type": "string"
},
"source": {
"type": "string"
},
"status": {
"type": "string"
},
"timestamp": {
"type": "string"
},
"uid": {
"type": "string"
}
}
},
"v1beta1.EventList": {
"id": "v1beta1.EventList",
"required": [
"apiVersion",
"annotations",
"kind",
"id",
"creationTimestamp",
"selfLink",
"uid",
"resourceVersion",
"namespace",
"items"
],
"properties": {
"annotations": {
"type": "v1beta1.TypeMeta.annotations"
},
"apiVersion": {
"type": "string"
},
"creationTimestamp": {
"type": "string"
},
"id": {
"type": "string"
},
"items": {
"type": "array",
"items": [
{
"$ref": "v1beta1.Event"
}
]
},
"kind": {
"type": "string"
},
"namespace": {
"type": "string"
},
"resourceVersion": {
"type": "uint64"
},
"selfLink": {
"type": "string"
},
"uid": {
"type": "string"
}
}
},
"v1beta1.ExecAction": {
"id": "v1beta1.ExecAction",
"properties": {
"command": {
"type": "array",
"items": [
{
"$ref": "string"
}
]
}
}
},
"v1beta1.GCEPersistentDisk": {
"id": "v1beta1.GCEPersistentDisk",
"required": [
"pdName"
],
"properties": {
"fsType": {
"type": "string"
},
"partition": {
"type": "integer",
"format": "int32"
},
"pdName": {
"type": "string"
},
"readOnly": {
"type": "boolean"
}
}
},
"v1beta1.GitRepo": {
"id": "v1beta1.GitRepo",
"required": [
"repository",
"revision"
],
"properties": {
"repository": {
"type": "string"
},
"revision": {
"type": "string"
}
}
},
"v1beta1.HTTPGetAction": {
"id": "v1beta1.HTTPGetAction",
"properties": {
"host": {
"type": "string"
},
"path": {
"type": "string"
},
"port": {
"type": "string"
}
}
},
"v1beta1.Handler": {
"id": "v1beta1.Handler",
"properties": {
"exec": {
"type": "v1beta1.ExecAction"
},
"httpGet": {
"type": "v1beta1.HTTPGetAction"
}
}
},
"v1beta1.HostDir": {
"id": "v1beta1.HostDir",
"required": [
"path"
],
"properties": {
"path": {
"type": "string"
}
}
},
"v1beta1.Lifecycle": {
"id": "v1beta1.Lifecycle",
"properties": {
"postStart": {
"type": "v1beta1.Handler"
},
"preStop": {
"type": "v1beta1.Handler"
}
}
},
"v1beta1.LivenessProbe": {
"id": "v1beta1.LivenessProbe",
"properties": {
"exec": {
"type": "v1beta1.ExecAction"
},
"httpGet": {
"type": "v1beta1.HTTPGetAction"
},
"initialDelaySeconds": {
"type": "integer",
"format": "int64"
},
"tcpSocket": {
"type": "v1beta1.TCPSocketAction"
}
}
},
"v1beta1.Minion": {
"id": "v1beta1.Minion",
"required": [
"creationTimestamp",
"selfLink",
"annotations",
"kind",
"id",
"uid",
"resourceVersion",
"apiVersion",
"namespace"
],
"properties": {
"annotations": {
"type": "v1beta1.TypeMeta.annotations"
},
"apiVersion": {
"type": "string"
},
"creationTimestamp": {
"type": "string"
},
"hostIP": {
"type": "string"
},
"id": {
"type": "string"
},
"kind": {
"type": "string"
},
"labels": {
"type": "v1beta1.Minion.labels"
},
"namespace": {
"type": "string"
},
"resourceVersion": {
"type": "uint64"
},
"resources": {
"type": "v1beta1.NodeResources"
},
"selfLink": {
"type": "string"
},
"uid": {
"type": "string"
}
}
},
"v1beta1.Minion.labels": {
"id": "v1beta1.Minion.labels",
"properties": {}
},
"v1beta1.MinionList": {
"id": "v1beta1.MinionList",
"required": [
"annotations",
"uid",
"resourceVersion",
"apiVersion",
"namespace",
"kind",
"id",
"creationTimestamp",
"selfLink",
"items"
],
"properties": {
"annotations": {
"type": "v1beta1.TypeMeta.annotations"
},
"apiVersion": {
"type": "string"
},
"creationTimestamp": {
"type": "string"
},
"id": {
"type": "string"
},
"items": {
"type": "array",
"items": [
{
"$ref": "v1beta1.Minion"
}
]
},
"kind": {
"type": "string"
},
"minions": {
"type": "array",
"items": [
{
"$ref": "v1beta1.Minion"
}
]
},
"namespace": {
"type": "string"
},
"resourceVersion": {
"type": "uint64"
},
"selfLink": {
"type": "string"
},
"uid": {
"type": "string"
}
}
},
"v1beta1.NodeResources": {
"id": "v1beta1.NodeResources",
"properties": {
"capacity": {
"type": "v1beta1.ResourceList"
}
}
},
"v1beta1.ObjectReference": {
"id": "v1beta1.ObjectReference",
"properties": {
"apiVersion": {
"type": "string"
},
"fieldPath": {
"type": "string"
},
"kind": {
"type": "string"
},
"name": {
"type": "string"
},
"namespace": {
"type": "string"
},
"resourceVersion": {
"type": "string"
},
"uid": {
"type": "string"
}
}
},
"v1beta1.Pod": {
"id": "v1beta1.Pod",
"required": [
"kind",
"creationTimestamp",
"selfLink",
"resourceVersion",
"namespace",
"id",
"uid",
"apiVersion",
"annotations"
],
"properties": {
"annotations": {
"type": "v1beta1.TypeMeta.annotations"
},
"apiVersion": {
"type": "string"
},
"creationTimestamp": {
"type": "string"
},
"currentState": {
"type": "v1beta1.PodState"
},
"desiredState": {
"type": "v1beta1.PodState"
},
"id": {
"type": "string"
},
"kind": {
"type": "string"
},
"labels": {
"type": "v1beta1.Pod.labels"
},
"namespace": {
"type": "string"
},
"nodeSelector": {
"type": "v1beta1.Pod.nodeSelector"
},
"resourceVersion": {
"type": "uint64"
},
"selfLink": {
"type": "string"
},
"uid": {
"type": "string"
}
}
},
"v1beta1.Pod.labels": {
"id": "v1beta1.Pod.labels",
"properties": {}
},
"v1beta1.Pod.nodeSelector": {
"id": "v1beta1.Pod.nodeSelector",
"properties": {}
},
"v1beta1.PodList": {
"id": "v1beta1.PodList",
"required": [
"uid",
"creationTimestamp",
"apiVersion",
"annotations",
"namespace",
"kind",
"id",
"selfLink",
"resourceVersion",
"items"
],
"properties": {
"annotations": {
"type": "v1beta1.TypeMeta.annotations"
},
"apiVersion": {
"type": "string"
},
"creationTimestamp": {
"type": "string"
},
"id": {
"type": "string"
},
"items": {
"type": "array",
"items": [
{
"$ref": "v1beta1.Pod"
}
]
},
"kind": {
"type": "string"
},
"namespace": {
"type": "string"
},
"resourceVersion": {
"type": "uint64"
},
"selfLink": {
"type": "string"
},
"uid": {
"type": "string"
}
}
},
"v1beta1.PodState": {
"id": "v1beta1.PodState",
"properties": {
"host": {
"type": "string"
},
"hostIP": {
"type": "string"
},
"info": {
"type": "v1beta1.PodInfo"
},
"manifest": {
"type": "v1beta1.ContainerManifest"
},
"message": {
"type": "string"
},
"podIP": {
"type": "string"
},
"status": {
"type": "v1beta1.PodStatus"
}
}
},
"v1beta1.PodTemplate": {
"id": "v1beta1.PodTemplate",
"properties": {
"desiredState": {
"type": "v1beta1.PodState"
},
"labels": {
"type": "v1beta1.PodTemplate.labels"
}
}
},
"v1beta1.PodTemplate.labels": {
"id": "v1beta1.PodTemplate.labels",
"properties": {}
},
"v1beta1.Port": {
"id": "v1beta1.Port",
"required": [
"containerPort"
],
"properties": {
"containerPort": {
"type": "integer",
"format": "int32"
},
"hostIP": {
"type": "string"
},
"hostPort": {
"type": "integer",
"format": "int32"
},
"name": {
"type": "string"
},
"protocol": {
"type": "v1beta1.Protocol"
}
}
},
"v1beta1.ReplicationController": {
"id": "v1beta1.ReplicationController",
"required": [
"apiVersion",
"namespace",
"kind",
"uid",
"creationTimestamp",
"selfLink",
"id",
"resourceVersion",
"annotations"
],
"properties": {
"annotations": {
"type": "v1beta1.TypeMeta.annotations"
},
"apiVersion": {
"type": "string"
},
"creationTimestamp": {
"type": "string"
},
"currentState": {
"type": "v1beta1.ReplicationControllerState"
},
"desiredState": {
"type": "v1beta1.ReplicationControllerState"
},
"id": {
"type": "string"
},
"kind": {
"type": "string"
},
"labels": {
"type": "v1beta1.ReplicationController.labels"
},
"namespace": {
"type": "string"
},
"resourceVersion": {
"type": "uint64"
},
"selfLink": {
"type": "string"
},
"uid": {
"type": "string"
}
}
},
"v1beta1.ReplicationController.labels": {
"id": "v1beta1.ReplicationController.labels",
"properties": {}
},
"v1beta1.ReplicationControllerList": {
"id": "v1beta1.ReplicationControllerList",
"required": [
"kind",
"resourceVersion",
"apiVersion",
"annotations",
"id",
"uid",
"creationTimestamp",
"selfLink",
"namespace",
"items"
],
"properties": {
"annotations": {
"type": "v1beta1.TypeMeta.annotations"
},
"apiVersion": {
"type": "string"
},
"creationTimestamp": {
"type": "string"
},
"id": {
"type": "string"
},
"items": {
"type": "array",
"items": [
{
"$ref": "v1beta1.ReplicationController"
}
]
},
"kind": {
"type": "string"
},
"namespace": {
"type": "string"
},
"resourceVersion": {
"type": "uint64"
},
"selfLink": {
"type": "string"
},
"uid": {
"type": "string"
}
}
},
"v1beta1.ReplicationControllerState": {
"id": "v1beta1.ReplicationControllerState",
"required": [
"replicas"
],
"properties": {
"podTemplate": {
"type": "v1beta1.PodTemplate"
},
"replicaSelector": {
"type": "v1beta1.ReplicationControllerState.replicaSelector"
},
"replicas": {
"type": "integer",
"format": "int32"
}
}
},
"v1beta1.ReplicationControllerState.replicaSelector": {
"id": "v1beta1.ReplicationControllerState.replicaSelector",
"properties": {}
},
"v1beta1.RestartPolicy": {
"id": "v1beta1.RestartPolicy",
"properties": {
"always": {
"type": "v1beta1.RestartPolicyAlways"
},
"never": {
"type": "v1beta1.RestartPolicyNever"
},
"onFailure": {
"type": "v1beta1.RestartPolicyOnFailure"
}
}
},
"v1beta1.RestartPolicyAlways": {
"id": "v1beta1.RestartPolicyAlways",
"properties": {}
},
"v1beta1.RestartPolicyNever": {
"id": "v1beta1.RestartPolicyNever",
"properties": {}
},
"v1beta1.RestartPolicyOnFailure": {
"id": "v1beta1.RestartPolicyOnFailure",
"properties": {}
},
"v1beta1.Service": {
"id": "v1beta1.Service",
"required": [
"id",
"selfLink",
"resourceVersion",
"namespace",
"kind",
"uid",
"creationTimestamp",
"apiVersion",
"annotations",
"port"
],
"properties": {
"annotations": {
"type": "v1beta1.TypeMeta.annotations"
},
"apiVersion": {
"type": "string"
},
"containerPort": {
"type": "string"
},
"createExternalLoadBalancer": {
"type": "boolean"
},
"creationTimestamp": {
"type": "string"
},
"id": {
"type": "string"
},
"kind": {
"type": "string"
},
"labels": {
"type": "v1beta1.Service.labels"
},
"namespace": {
"type": "string"
},
"port": {
"type": "integer",
"format": "int32"
},
"portalIP": {
"type": "string"
},
"protocol": {
"type": "v1beta1.Protocol"
},
"proxyPort": {
"type": "integer",
"format": "int32"
},
"publicIPs": {
"type": "array",
"items": [
{
"$ref": "string"
}
]
},
"resourceVersion": {
"type": "uint64"
},
"selector": {
"type": "v1beta1.Service.selector"
},
"selfLink": {
"type": "string"
},
"uid": {
"type": "string"
}
}
},
"v1beta1.Service.labels": {
"id": "v1beta1.Service.labels",
"properties": {}
},
"v1beta1.Service.selector": {
"id": "v1beta1.Service.selector",
"properties": {}
},
"v1beta1.ServiceList": {
"id": "v1beta1.ServiceList",
"required": [
"apiVersion",
"annotations",
"kind",
"uid",
"selfLink",
"namespace",
"id",
"creationTimestamp",
"resourceVersion",
"items"
],
"properties": {
"annotations": {
"type": "v1beta1.TypeMeta.annotations"
},
"apiVersion": {
"type": "string"
},
"creationTimestamp": {
"type": "string"
},
"id": {
"type": "string"
},
"items": {
"type": "array",
"items": [
{
"$ref": "v1beta1.Service"
}
]
},
"kind": {
"type": "string"
},
"namespace": {
"type": "string"
},
"resourceVersion": {
"type": "uint64"
},
"selfLink": {
"type": "string"
},
"uid": {
"type": "string"
}
}
},
"v1beta1.TCPSocketAction": {
"id": "v1beta1.TCPSocketAction",
"properties": {
"port": {
"type": "string"
}
}
},
"v1beta1.Volume": {
"id": "v1beta1.Volume",
"required": [
"name",
"source"
],
"properties": {
"name": {
"type": "string"
},
"source": {
"type": "v1beta1.VolumeSource"
}
}
},
"v1beta1.VolumeMount": {
"id": "v1beta1.VolumeMount",
"required": [
"name"
],
"properties": {
"mountPath": {
"type": "string"
},
"mountType": {
"type": "string"
},
"name": {
"type": "string"
},
"path": {
"type": "string"
},
"readOnly": {
"type": "boolean"
}
}
},
"v1beta1.VolumeSource": {
"id": "v1beta1.VolumeSource",
"required": [
"hostDir",
"emptyDir",
"persistentDisk",
"gitRepo"
],
"properties": {
"emptyDir": {
"type": "v1beta1.EmptyDir"
},
"gitRepo": {
"type": "v1beta1.GitRepo"
},
"hostDir": {
"type": "v1beta1.HostDir"
},
"persistentDisk": {
"type": "v1beta1.GCEPersistentDisk"
}
}
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment