From 6c53d3b4621631700efd18b0ca1805621391fa08 Mon Sep 17 00:00:00 2001 From: Brendan Burns Date: Wed, 19 Nov 2014 21:25:24 -0800 Subject: [PATCH] Add a swagger schema validator, for validating client side json files. --- pkg/api/validation/schema.go | 142 ++ pkg/api/validation/schema_test.go | 279 +++ pkg/api/validation/v1beta1-swagger.json | 2095 +++++++++++++++++++++++ 3 files changed, 2516 insertions(+) create mode 100644 pkg/api/validation/schema.go create mode 100644 pkg/api/validation/schema_test.go create mode 100644 pkg/api/validation/v1beta1-swagger.json diff --git a/pkg/api/validation/schema.go b/pkg/api/validation/schema.go new file mode 100644 index 00000000000..82457f9cff4 --- /dev/null +++ b/pkg/api/validation/schema.go @@ -0,0 +1,142 @@ +/* +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 +} diff --git a/pkg/api/validation/schema_test.go b/pkg/api/validation/schema_test.go new file mode 100644 index 00000000000..e44f1190e7d --- /dev/null +++ b/pkg/api/validation/schema_test.go @@ -0,0 +1,279 @@ +/* +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) + } + } +} diff --git a/pkg/api/validation/v1beta1-swagger.json b/pkg/api/validation/v1beta1-swagger.json new file mode 100644 index 00000000000..dfcc371bf6d --- /dev/null +++ b/pkg/api/validation/v1beta1-swagger.json @@ -0,0 +1,2095 @@ +{ + "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" + } + } + } + } + }