mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
Fork API types.
This commit is contained in:
parent
cb28f25b1b
commit
bf5ae4bb9d
@ -1,5 +1,6 @@
|
||||
{
|
||||
"id": "nginxController",
|
||||
"apiVersion": "v1beta1",
|
||||
"desiredState": {
|
||||
"replicas": 2,
|
||||
"replicaSelector": {"name": "nginx"},
|
||||
|
@ -157,7 +157,7 @@ func runAtomicPutTest(c *client.Client) {
|
||||
var svc api.Service
|
||||
err := c.Post().Path("services").Body(
|
||||
api.Service{
|
||||
JSONBase: api.JSONBase{ID: "atomicService"},
|
||||
JSONBase: api.JSONBase{ID: "atomicService", APIVersion: "v1beta1"},
|
||||
Port: 12345,
|
||||
Labels: map[string]string{
|
||||
"name": "atomicService",
|
||||
|
@ -41,10 +41,10 @@ KUBE_COVER="-cover -covermode=atomic -coverprofile=\"tmp.out\""
|
||||
cd "${KUBE_TARGET}"
|
||||
|
||||
if [ "$1" != "" ]; then
|
||||
go test -race $KUBE_COVER "$KUBE_GO_PACKAGE/$1" "${@:2}"
|
||||
go test -race -timeout 30s $KUBE_COVER "$KUBE_GO_PACKAGE/$1" "${@:2}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
for package in $(find_test_dirs); do
|
||||
go test -race $KUBE_COVER "${KUBE_GO_PACKAGE}/${package}" "${@:2}"
|
||||
go test -race -timeout 30s $KUBE_COVER "${KUBE_GO_PACKAGE}/${package}" "${@:2}"
|
||||
done
|
||||
|
@ -28,8 +28,11 @@ func TestAPIObject(t *testing.T) {
|
||||
Object APIObject `yaml:"object,omitempty" json:"object,omitempty"`
|
||||
EmptyObject APIObject `yaml:"emptyObject,omitempty" json:"emptyObject,omitempty"`
|
||||
}
|
||||
|
||||
AddKnownTypes(EmbeddedTest{})
|
||||
convert := func(obj interface{}) (interface{}, error) { return obj, nil }
|
||||
AddKnownTypes("", EmbeddedTest{})
|
||||
AddKnownTypes("v1beta1", EmbeddedTest{})
|
||||
AddExternalConversion("EmbeddedTest", convert)
|
||||
AddInternalConversion("EmbeddedTest", convert)
|
||||
|
||||
outer := &EmbeddedTest{
|
||||
JSONBase: JSONBase{ID: "outer"},
|
||||
|
@ -21,13 +21,18 @@ import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"gopkg.in/v1/yaml"
|
||||
)
|
||||
|
||||
var knownTypes = map[string]reflect.Type{}
|
||||
type ConversionFunc func(input interface{}) (output interface{}, err error)
|
||||
|
||||
var versionMap = map[string]map[string]reflect.Type{}
|
||||
var externalFuncs = map[string]ConversionFunc{}
|
||||
var internalFuncs = map[string]ConversionFunc{}
|
||||
|
||||
func init() {
|
||||
AddKnownTypes(
|
||||
AddKnownTypes("",
|
||||
PodList{},
|
||||
Pod{},
|
||||
ReplicationControllerList{},
|
||||
@ -40,17 +45,43 @@ func init() {
|
||||
ServerOpList{},
|
||||
ServerOp{},
|
||||
)
|
||||
AddKnownTypes("v1beta1",
|
||||
v1beta1.PodList{},
|
||||
v1beta1.Pod{},
|
||||
v1beta1.ReplicationControllerList{},
|
||||
v1beta1.ReplicationController{},
|
||||
v1beta1.ServiceList{},
|
||||
v1beta1.Service{},
|
||||
v1beta1.MinionList{},
|
||||
v1beta1.Minion{},
|
||||
v1beta1.Status{},
|
||||
v1beta1.ServerOpList{},
|
||||
v1beta1.ServerOp{},
|
||||
)
|
||||
}
|
||||
|
||||
// AddKnownTypes registers the types of the arguments to the marshaller of the package api.
|
||||
// Encode() refuses the object unless its type is registered with AddKnownTypes.
|
||||
func AddKnownTypes(types ...interface{}) {
|
||||
func AddKnownTypes(version string, types ...interface{}) {
|
||||
knownTypes, found := versionMap[version]
|
||||
if !found {
|
||||
knownTypes = map[string]reflect.Type{}
|
||||
versionMap[version] = knownTypes
|
||||
}
|
||||
for _, obj := range types {
|
||||
t := reflect.TypeOf(obj)
|
||||
knownTypes[t.Name()] = t
|
||||
}
|
||||
}
|
||||
|
||||
func AddExternalConversion(name string, fn ConversionFunc) {
|
||||
externalFuncs[name] = fn
|
||||
}
|
||||
|
||||
func AddInternalConversion(name string, fn ConversionFunc) {
|
||||
internalFuncs[name] = fn
|
||||
}
|
||||
|
||||
// FindJSONBase takes an arbitary api type, returns pointer to its JSONBase field.
|
||||
// obj must be a pointer to an api type.
|
||||
func FindJSONBase(obj interface{}) (*JSONBase, error) {
|
||||
@ -85,11 +116,32 @@ func FindJSONBaseRO(obj interface{}) (JSONBase, error) {
|
||||
// format.
|
||||
func Encode(obj interface{}) (data []byte, err error) {
|
||||
obj = checkPtr(obj)
|
||||
jsonBase, err := prepareEncode(obj)
|
||||
base, err := prepareEncode(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(base.APIVersion) == 0 {
|
||||
out, err := externalize(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, jsonBase, err := nameAndJSONBase(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
jsonBase.Kind = ""
|
||||
obj = out
|
||||
_, err = prepareEncode(out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
data, err = json.MarshalIndent(obj, "", " ")
|
||||
_, jsonBase, err := nameAndJSONBase(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
jsonBase.Kind = ""
|
||||
return data, err
|
||||
}
|
||||
@ -109,8 +161,12 @@ func prepareEncode(obj interface{}) (*JSONBase, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
knownTypes, found := versionMap[jsonBase.APIVersion]
|
||||
if !found {
|
||||
return nil, fmt.Errorf("struct %s, %v won't be unmarshalable because its not in known versions", jsonBase.APIVersion, obj)
|
||||
}
|
||||
if _, contains := knownTypes[name]; !contains {
|
||||
return nil, fmt.Errorf("struct %v won't be unmarshalable because it's not in knownTypes", name)
|
||||
return nil, fmt.Errorf("struct %s won't be unmarshalable because it's not in knownTypes", name)
|
||||
}
|
||||
jsonBase.Kind = name
|
||||
return jsonBase, nil
|
||||
@ -131,29 +187,48 @@ func nameAndJSONBase(obj interface{}) (string, *JSONBase, error) {
|
||||
if !jsonBase.IsValid() {
|
||||
return "", nil, fmt.Errorf("struct %v lacks embedded JSON type", name)
|
||||
}
|
||||
return name, jsonBase.Addr().Interface().(*JSONBase), nil
|
||||
output, ok := jsonBase.Addr().Interface().(*JSONBase)
|
||||
if !ok {
|
||||
internal, err := internalize(jsonBase.Addr().Interface())
|
||||
if err != nil {
|
||||
return name, nil, err
|
||||
}
|
||||
output = internal.(*JSONBase)
|
||||
}
|
||||
return name, output, nil
|
||||
}
|
||||
|
||||
// Decode converts a JSON string back into a pointer to an api object. Deduces the type
|
||||
// based upon the Kind field (set by encode).
|
||||
func Decode(data []byte) (interface{}, error) {
|
||||
findKind := struct {
|
||||
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
|
||||
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
|
||||
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
|
||||
}{}
|
||||
// yaml is a superset of json, so we use it to decode here. That way, we understand both.
|
||||
err := yaml.Unmarshal(data, &findKind)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't get kind: %#v", err)
|
||||
}
|
||||
knownTypes, found := versionMap[findKind.APIVersion]
|
||||
if !found {
|
||||
return nil, fmt.Errorf("Unknown api verson: %s", findKind.APIVersion)
|
||||
}
|
||||
objType, found := knownTypes[findKind.Kind]
|
||||
if !found {
|
||||
return nil, fmt.Errorf("%v is not a known type", findKind.Kind)
|
||||
return nil, fmt.Errorf("%#v is not a known type for decoding", findKind)
|
||||
}
|
||||
obj := reflect.New(objType).Interface()
|
||||
err = yaml.Unmarshal(data, obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(findKind.APIVersion) != 0 {
|
||||
obj, err = internalize(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
_, jsonBase, err := nameAndJSONBase(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -167,10 +242,16 @@ func Decode(data []byte) (interface{}, error) {
|
||||
// if data.Kind is set and doesn't match the type of obj. Obj should be a
|
||||
// pointer to an api type.
|
||||
func DecodeInto(data []byte, obj interface{}) error {
|
||||
err := yaml.Unmarshal(data, obj)
|
||||
internal, err := Decode(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v := reflect.ValueOf(obj)
|
||||
iv := reflect.ValueOf(internal)
|
||||
if !iv.Type().AssignableTo(v.Type()) {
|
||||
return fmt.Errorf("%s is not assignable to %s", v.Type(), iv.Type())
|
||||
}
|
||||
v.Elem().Set(iv.Elem())
|
||||
name, jsonBase, err := nameAndJSONBase(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -182,3 +263,665 @@ func DecodeInto(data []byte, obj interface{}) error {
|
||||
jsonBase.Kind = ""
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: Switch to registered functions for each type.
|
||||
func internalize(obj interface{}) (interface{}, error) {
|
||||
v := reflect.ValueOf(obj)
|
||||
if v.Kind() != reflect.Ptr {
|
||||
value := reflect.New(v.Type())
|
||||
value.Elem().Set(v)
|
||||
result, err := internalize(value.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return reflect.ValueOf(result).Elem().Interface(), nil
|
||||
}
|
||||
switch cObj := obj.(type) {
|
||||
case *v1beta1.JSONBase:
|
||||
obj := JSONBase(*cObj)
|
||||
return &obj, nil
|
||||
case *v1beta1.PodList:
|
||||
var items []Pod
|
||||
if cObj.Items != nil {
|
||||
items = make([]Pod, len(cObj.Items))
|
||||
for ix := range cObj.Items {
|
||||
iObj, err := internalize(cObj.Items[ix])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items[ix] = iObj.(Pod)
|
||||
}
|
||||
}
|
||||
result := PodList{
|
||||
JSONBase: JSONBase(cObj.JSONBase),
|
||||
Items: items,
|
||||
}
|
||||
result.APIVersion = ""
|
||||
return &result, nil
|
||||
case *v1beta1.Pod:
|
||||
current, err := internalize(cObj.CurrentState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
desired, err := internalize(cObj.DesiredState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := Pod{
|
||||
JSONBase: JSONBase(cObj.JSONBase),
|
||||
Labels: cObj.Labels,
|
||||
CurrentState: current.(PodState),
|
||||
DesiredState: desired.(PodState),
|
||||
}
|
||||
result.APIVersion = ""
|
||||
return &result, nil
|
||||
case *v1beta1.PodState:
|
||||
manifest, err := internalize(cObj.Manifest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := PodState{
|
||||
Manifest: manifest.(ContainerManifest),
|
||||
Status: PodStatus(cObj.Status),
|
||||
Host: cObj.Host,
|
||||
HostIP: cObj.HostIP,
|
||||
PodIP: cObj.PodIP,
|
||||
Info: PodInfo(cObj.Info),
|
||||
}
|
||||
return &result, nil
|
||||
case *v1beta1.ContainerManifest:
|
||||
var volumes []Volume
|
||||
if cObj.Volumes != nil {
|
||||
volumes = make([]Volume, len(cObj.Volumes))
|
||||
for ix := range cObj.Volumes {
|
||||
v, err := internalize(cObj.Volumes[ix])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
volumes[ix] = *(v.(*Volume))
|
||||
}
|
||||
}
|
||||
var containers []Container
|
||||
if cObj.Containers != nil {
|
||||
containers = make([]Container, len(cObj.Containers))
|
||||
for ix := range cObj.Containers {
|
||||
v, err := internalize(cObj.Containers[ix])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
containers[ix] = v.(Container)
|
||||
}
|
||||
}
|
||||
result := ContainerManifest{
|
||||
Version: cObj.Version,
|
||||
ID: cObj.ID,
|
||||
Volumes: volumes,
|
||||
Containers: containers,
|
||||
}
|
||||
return &result, nil
|
||||
case *v1beta1.Volume:
|
||||
var src *VolumeSource
|
||||
if cObj.Source != nil {
|
||||
obj, err := internalize(cObj.Source)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
src = obj.(*VolumeSource)
|
||||
}
|
||||
result := &Volume{
|
||||
Name: cObj.Name,
|
||||
Source: src,
|
||||
}
|
||||
return &result, nil
|
||||
case *v1beta1.VolumeSource:
|
||||
var hostDir *HostDirectory
|
||||
if cObj.HostDirectory != nil {
|
||||
hostDir = &HostDirectory{
|
||||
Path: cObj.HostDirectory.Path,
|
||||
}
|
||||
}
|
||||
var emptyDir *EmptyDirectory
|
||||
if cObj.EmptyDirectory != nil {
|
||||
emptyDir = &EmptyDirectory{}
|
||||
}
|
||||
result := VolumeSource{
|
||||
HostDirectory: hostDir,
|
||||
EmptyDirectory: emptyDir,
|
||||
}
|
||||
return &result, nil
|
||||
case *v1beta1.Container:
|
||||
ports := make([]Port, len(cObj.Ports))
|
||||
for ix := range cObj.Ports {
|
||||
p, err := internalize(cObj.Ports[ix])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ports[ix] = (p.(Port))
|
||||
}
|
||||
env := make([]EnvVar, len(cObj.Env))
|
||||
for ix := range cObj.Env {
|
||||
e, err := internalize(cObj.Env[ix])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
env[ix] = e.(EnvVar)
|
||||
}
|
||||
mounts := make([]VolumeMount, len(cObj.VolumeMounts))
|
||||
for ix := range cObj.VolumeMounts {
|
||||
v, err := internalize(cObj.VolumeMounts[ix])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mounts[ix] = v.(VolumeMount)
|
||||
}
|
||||
var liveness *LivenessProbe
|
||||
if cObj.LivenessProbe != nil {
|
||||
probe, err := internalize(*cObj.LivenessProbe)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
live := probe.(LivenessProbe)
|
||||
liveness = &live
|
||||
}
|
||||
result := Container{
|
||||
Name: cObj.Name,
|
||||
Image: cObj.Image,
|
||||
Command: cObj.Command,
|
||||
WorkingDir: cObj.WorkingDir,
|
||||
Ports: ports,
|
||||
Env: env,
|
||||
Memory: cObj.Memory,
|
||||
CPU: cObj.CPU,
|
||||
VolumeMounts: mounts,
|
||||
LivenessProbe: liveness,
|
||||
}
|
||||
return &result, nil
|
||||
case *v1beta1.Port:
|
||||
result := Port(*cObj)
|
||||
return &result, nil
|
||||
case *v1beta1.EnvVar:
|
||||
result := EnvVar(*cObj)
|
||||
return &result, nil
|
||||
case *v1beta1.VolumeMount:
|
||||
result := VolumeMount(*cObj)
|
||||
return &result, nil
|
||||
case *v1beta1.LivenessProbe:
|
||||
var http *HTTPGetProbe
|
||||
if cObj.HTTPGet != nil {
|
||||
httpProbe := HTTPGetProbe(*cObj.HTTPGet)
|
||||
http = &httpProbe
|
||||
}
|
||||
result := LivenessProbe{
|
||||
Type: cObj.Type,
|
||||
HTTPGet: http,
|
||||
InitialDelaySeconds: cObj.InitialDelaySeconds,
|
||||
}
|
||||
return &result, nil
|
||||
case *v1beta1.ReplicationControllerList:
|
||||
var items []ReplicationController
|
||||
if cObj.Items != nil {
|
||||
items := make([]ReplicationController, len(cObj.Items))
|
||||
for ix := range cObj.Items {
|
||||
rc, err := internalize(cObj.Items[ix])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items[ix] = rc.(ReplicationController)
|
||||
}
|
||||
}
|
||||
result := ReplicationControllerList{
|
||||
JSONBase: JSONBase(cObj.JSONBase),
|
||||
Items: items,
|
||||
}
|
||||
result.APIVersion = ""
|
||||
return &result, nil
|
||||
case *v1beta1.ReplicationController:
|
||||
desired, err := internalize(cObj.DesiredState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := ReplicationController{
|
||||
JSONBase: JSONBase(cObj.JSONBase),
|
||||
DesiredState: desired.(ReplicationControllerState),
|
||||
Labels: cObj.Labels,
|
||||
}
|
||||
result.APIVersion = ""
|
||||
return &result, nil
|
||||
case *v1beta1.ReplicationControllerState:
|
||||
template, err := internalize(cObj.PodTemplate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := ReplicationControllerState{
|
||||
Replicas: cObj.Replicas,
|
||||
ReplicaSelector: cObj.ReplicaSelector,
|
||||
PodTemplate: template.(PodTemplate),
|
||||
}
|
||||
return &result, nil
|
||||
case *v1beta1.PodTemplate:
|
||||
desired, err := internalize(cObj.DesiredState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &PodTemplate{
|
||||
DesiredState: desired.(PodState),
|
||||
Labels: cObj.Labels,
|
||||
}, nil
|
||||
case *v1beta1.ServiceList:
|
||||
var services []Service
|
||||
if cObj.Items != nil {
|
||||
services = make([]Service, len(cObj.Items))
|
||||
for ix := range cObj.Items {
|
||||
s, err := internalize(cObj.Items[ix])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
services[ix] = s.(Service)
|
||||
services[ix].APIVersion = ""
|
||||
}
|
||||
}
|
||||
result := ServiceList{
|
||||
JSONBase: JSONBase(cObj.JSONBase),
|
||||
Items: services,
|
||||
}
|
||||
result.APIVersion = ""
|
||||
return &result, nil
|
||||
case *v1beta1.Service:
|
||||
result := Service{
|
||||
JSONBase: JSONBase(cObj.JSONBase),
|
||||
Port: cObj.Port,
|
||||
Labels: cObj.Labels,
|
||||
Selector: cObj.Selector,
|
||||
CreateExternalLoadBalancer: cObj.CreateExternalLoadBalancer,
|
||||
ContainerPort: cObj.ContainerPort,
|
||||
}
|
||||
result.APIVersion = ""
|
||||
return &result, nil
|
||||
case *v1beta1.MinionList:
|
||||
minions := make([]Minion, len(cObj.Items))
|
||||
for ix := range cObj.Items {
|
||||
m, err := internalize(cObj.Items[ix])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
minions[ix] = m.(Minion)
|
||||
}
|
||||
result := MinionList{
|
||||
JSONBase: JSONBase(cObj.JSONBase),
|
||||
Items: minions,
|
||||
}
|
||||
result.APIVersion = ""
|
||||
return &result, nil
|
||||
case *v1beta1.Minion:
|
||||
result := Minion{
|
||||
JSONBase: JSONBase(cObj.JSONBase),
|
||||
HostIP: cObj.HostIP,
|
||||
}
|
||||
result.APIVersion = ""
|
||||
return &result, nil
|
||||
case *v1beta1.Status:
|
||||
result := Status{
|
||||
JSONBase: JSONBase(cObj.JSONBase),
|
||||
Status: cObj.Status,
|
||||
Details: cObj.Details,
|
||||
Code: cObj.Code,
|
||||
}
|
||||
result.APIVersion = ""
|
||||
return &result, nil
|
||||
case *v1beta1.ServerOpList:
|
||||
ops := make([]ServerOp, len(cObj.Items))
|
||||
for ix := range cObj.Items {
|
||||
o, err := internalize(cObj.Items[ix])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ops[ix] = o.(ServerOp)
|
||||
}
|
||||
result := ServerOpList{
|
||||
JSONBase: JSONBase(cObj.JSONBase),
|
||||
Items: ops,
|
||||
}
|
||||
result.APIVersion = ""
|
||||
return &result, nil
|
||||
case *v1beta1.ServerOp:
|
||||
result := ServerOp{
|
||||
JSONBase: JSONBase(cObj.JSONBase),
|
||||
}
|
||||
result.APIVersion = ""
|
||||
return &result, nil
|
||||
default:
|
||||
fn, ok := internalFuncs[reflect.ValueOf(cObj).Elem().Type().Name()]
|
||||
if !ok {
|
||||
fmt.Printf("unknown object to internalize: %s", reflect.ValueOf(cObj).Type().Name())
|
||||
panic(fmt.Sprintf("unknown object to internalize: %s", reflect.ValueOf(cObj).Type().Name()))
|
||||
}
|
||||
return fn(cObj)
|
||||
}
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
// TODO: switch to registered functions for each type.
|
||||
func externalize(obj interface{}) (interface{}, error) {
|
||||
v := reflect.ValueOf(obj)
|
||||
if v.Kind() != reflect.Ptr {
|
||||
value := reflect.New(v.Type())
|
||||
value.Elem().Set(v)
|
||||
result, err := externalize(value.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return reflect.ValueOf(result).Elem().Interface(), nil
|
||||
}
|
||||
switch cObj := obj.(type) {
|
||||
case *PodList:
|
||||
var items []v1beta1.Pod
|
||||
if cObj.Items != nil {
|
||||
items = make([]v1beta1.Pod, len(cObj.Items))
|
||||
for ix := range cObj.Items {
|
||||
iObj, err := externalize(cObj.Items[ix])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items[ix] = iObj.(v1beta1.Pod)
|
||||
}
|
||||
}
|
||||
result := v1beta1.PodList{
|
||||
JSONBase: v1beta1.JSONBase(cObj.JSONBase),
|
||||
Items: items,
|
||||
}
|
||||
result.APIVersion = "v1beta1"
|
||||
return &result, nil
|
||||
case *Pod:
|
||||
current, err := externalize(cObj.CurrentState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
desired, err := externalize(cObj.DesiredState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := v1beta1.Pod{
|
||||
JSONBase: v1beta1.JSONBase(cObj.JSONBase),
|
||||
Labels: cObj.Labels,
|
||||
CurrentState: current.(v1beta1.PodState),
|
||||
DesiredState: desired.(v1beta1.PodState),
|
||||
}
|
||||
result.APIVersion = "v1beta1"
|
||||
return &result, nil
|
||||
case *PodState:
|
||||
manifest, err := externalize(cObj.Manifest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := v1beta1.PodState{
|
||||
Manifest: manifest.(v1beta1.ContainerManifest),
|
||||
Status: v1beta1.PodStatus(cObj.Status),
|
||||
Host: cObj.Host,
|
||||
HostIP: cObj.HostIP,
|
||||
PodIP: cObj.PodIP,
|
||||
Info: v1beta1.PodInfo(cObj.Info),
|
||||
}
|
||||
return &result, nil
|
||||
case *ContainerManifest:
|
||||
var volumes []v1beta1.Volume
|
||||
if cObj.Volumes != nil {
|
||||
volumes = make([]v1beta1.Volume, len(cObj.Volumes))
|
||||
for ix := range cObj.Volumes {
|
||||
v, err := externalize(cObj.Volumes[ix])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
volumes[ix] = *(v.(*v1beta1.Volume))
|
||||
}
|
||||
}
|
||||
var containers []v1beta1.Container
|
||||
if cObj.Containers != nil {
|
||||
containers = make([]v1beta1.Container, len(cObj.Containers))
|
||||
for ix := range cObj.Containers {
|
||||
v, err := externalize(cObj.Containers[ix])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
containers[ix] = v.(v1beta1.Container)
|
||||
}
|
||||
}
|
||||
result := v1beta1.ContainerManifest{
|
||||
Version: cObj.Version,
|
||||
ID: cObj.ID,
|
||||
Volumes: volumes,
|
||||
Containers: containers,
|
||||
}
|
||||
return &result, nil
|
||||
case *Volume:
|
||||
var src *v1beta1.VolumeSource
|
||||
if cObj.Source != nil {
|
||||
obj, err := externalize(cObj.Source)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
src = obj.(*v1beta1.VolumeSource)
|
||||
}
|
||||
result := &v1beta1.Volume{
|
||||
Name: cObj.Name,
|
||||
Source: src,
|
||||
}
|
||||
return &result, nil
|
||||
case *VolumeSource:
|
||||
var hostDir *v1beta1.HostDirectory
|
||||
if cObj.HostDirectory != nil {
|
||||
hostDir = &v1beta1.HostDirectory{
|
||||
Path: cObj.HostDirectory.Path,
|
||||
}
|
||||
}
|
||||
var emptyDir *v1beta1.EmptyDirectory
|
||||
if cObj.EmptyDirectory != nil {
|
||||
emptyDir = &v1beta1.EmptyDirectory{}
|
||||
}
|
||||
result := v1beta1.VolumeSource{
|
||||
HostDirectory: hostDir,
|
||||
EmptyDirectory: emptyDir,
|
||||
}
|
||||
return &result, nil
|
||||
case *Container:
|
||||
ports := make([]v1beta1.Port, len(cObj.Ports))
|
||||
for ix := range cObj.Ports {
|
||||
p, err := externalize(cObj.Ports[ix])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ports[ix] = p.(v1beta1.Port)
|
||||
}
|
||||
env := make([]v1beta1.EnvVar, len(cObj.Env))
|
||||
for ix := range cObj.Env {
|
||||
e, err := externalize(cObj.Env[ix])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
env[ix] = e.(v1beta1.EnvVar)
|
||||
}
|
||||
mounts := make([]v1beta1.VolumeMount, len(cObj.VolumeMounts))
|
||||
for ix := range cObj.VolumeMounts {
|
||||
v, err := externalize(cObj.VolumeMounts[ix])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mounts[ix] = v.(v1beta1.VolumeMount)
|
||||
}
|
||||
var liveness *v1beta1.LivenessProbe
|
||||
if cObj.LivenessProbe != nil {
|
||||
probe, err := externalize(*cObj.LivenessProbe)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
live := probe.(v1beta1.LivenessProbe)
|
||||
liveness = &live
|
||||
}
|
||||
result := v1beta1.Container{
|
||||
Name: cObj.Name,
|
||||
Image: cObj.Image,
|
||||
Command: cObj.Command,
|
||||
WorkingDir: cObj.WorkingDir,
|
||||
Ports: ports,
|
||||
Env: env,
|
||||
Memory: cObj.Memory,
|
||||
CPU: cObj.CPU,
|
||||
VolumeMounts: mounts,
|
||||
LivenessProbe: liveness,
|
||||
}
|
||||
return &result, nil
|
||||
case *Port:
|
||||
result := v1beta1.Port(*cObj)
|
||||
return &result, nil
|
||||
case *EnvVar:
|
||||
result := v1beta1.EnvVar(*cObj)
|
||||
return &result, nil
|
||||
case *VolumeMount:
|
||||
result := v1beta1.VolumeMount(*cObj)
|
||||
return &result, nil
|
||||
case *LivenessProbe:
|
||||
var http *v1beta1.HTTPGetProbe
|
||||
if cObj.HTTPGet != nil {
|
||||
httpProbe := v1beta1.HTTPGetProbe(*cObj.HTTPGet)
|
||||
http = &httpProbe
|
||||
}
|
||||
result := v1beta1.LivenessProbe{
|
||||
Type: cObj.Type,
|
||||
HTTPGet: http,
|
||||
InitialDelaySeconds: cObj.InitialDelaySeconds,
|
||||
}
|
||||
return &result, nil
|
||||
case *ReplicationControllerList:
|
||||
items := make([]v1beta1.ReplicationController, len(cObj.Items))
|
||||
for ix := range cObj.Items {
|
||||
rc, err := externalize(cObj.Items[ix])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items[ix] = rc.(v1beta1.ReplicationController)
|
||||
}
|
||||
result := v1beta1.ReplicationControllerList{
|
||||
JSONBase: v1beta1.JSONBase(cObj.JSONBase),
|
||||
Items: items,
|
||||
}
|
||||
result.APIVersion = "v1beta1"
|
||||
return &result, nil
|
||||
case *ReplicationController:
|
||||
desired, err := externalize(cObj.DesiredState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := v1beta1.ReplicationController{
|
||||
JSONBase: v1beta1.JSONBase(cObj.JSONBase),
|
||||
DesiredState: desired.(v1beta1.ReplicationControllerState),
|
||||
Labels: cObj.Labels,
|
||||
}
|
||||
result.APIVersion = "v1beta1"
|
||||
return &result, nil
|
||||
case *ReplicationControllerState:
|
||||
template, err := externalize(cObj.PodTemplate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := v1beta1.ReplicationControllerState{
|
||||
Replicas: cObj.Replicas,
|
||||
ReplicaSelector: cObj.ReplicaSelector,
|
||||
PodTemplate: template.(v1beta1.PodTemplate),
|
||||
}
|
||||
return &result, nil
|
||||
case *PodTemplate:
|
||||
desired, err := externalize(cObj.DesiredState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v1beta1.PodTemplate{
|
||||
DesiredState: desired.(v1beta1.PodState),
|
||||
Labels: cObj.Labels,
|
||||
}, nil
|
||||
case *ServiceList:
|
||||
services := make([]v1beta1.Service, len(cObj.Items))
|
||||
for ix := range cObj.Items {
|
||||
s, err := externalize(cObj.Items[ix])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
services[ix] = s.(v1beta1.Service)
|
||||
}
|
||||
result := v1beta1.ServiceList{
|
||||
JSONBase: v1beta1.JSONBase(cObj.JSONBase),
|
||||
Items: services,
|
||||
}
|
||||
result.APIVersion = "v1beta1"
|
||||
return &result, nil
|
||||
case *Service:
|
||||
result := v1beta1.Service{
|
||||
JSONBase: v1beta1.JSONBase(cObj.JSONBase),
|
||||
Port: cObj.Port,
|
||||
Labels: cObj.Labels,
|
||||
Selector: cObj.Selector,
|
||||
CreateExternalLoadBalancer: cObj.CreateExternalLoadBalancer,
|
||||
ContainerPort: cObj.ContainerPort,
|
||||
}
|
||||
result.APIVersion = "v1beta1"
|
||||
return &result, nil
|
||||
case *MinionList:
|
||||
minions := make([]v1beta1.Minion, len(cObj.Items))
|
||||
for ix := range cObj.Items {
|
||||
m, err := externalize(cObj.Items[ix])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
minions[ix] = m.(v1beta1.Minion)
|
||||
}
|
||||
result := v1beta1.MinionList{
|
||||
JSONBase: v1beta1.JSONBase(cObj.JSONBase),
|
||||
Items: minions,
|
||||
}
|
||||
result.APIVersion = "v1beta1"
|
||||
return &result, nil
|
||||
case *Minion:
|
||||
result := v1beta1.Minion{
|
||||
JSONBase: v1beta1.JSONBase(cObj.JSONBase),
|
||||
HostIP: cObj.HostIP,
|
||||
}
|
||||
result.APIVersion = "v1beta1"
|
||||
return &result, nil
|
||||
case *Status:
|
||||
result := v1beta1.Status{
|
||||
JSONBase: v1beta1.JSONBase(cObj.JSONBase),
|
||||
Status: cObj.Status,
|
||||
Details: cObj.Details,
|
||||
Code: cObj.Code,
|
||||
}
|
||||
result.APIVersion = "v1beta1"
|
||||
return &result, nil
|
||||
case *ServerOpList:
|
||||
ops := make([]v1beta1.ServerOp, len(cObj.Items))
|
||||
for ix := range cObj.Items {
|
||||
o, err := externalize(cObj.Items[ix])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ops[ix] = o.(v1beta1.ServerOp)
|
||||
}
|
||||
result := v1beta1.ServerOpList{
|
||||
JSONBase: v1beta1.JSONBase(cObj.JSONBase),
|
||||
Items: ops,
|
||||
}
|
||||
result.APIVersion = "v1beta1"
|
||||
return &result, nil
|
||||
case *ServerOp:
|
||||
result := v1beta1.ServerOp{
|
||||
JSONBase: v1beta1.JSONBase(cObj.JSONBase),
|
||||
}
|
||||
result.APIVersion = "v1beta1"
|
||||
return &result, nil
|
||||
default:
|
||||
fn, ok := externalFuncs[reflect.ValueOf(cObj).Elem().Type().Name()]
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("Unknown object to externalize: %#v %s", cObj, reflect.ValueOf(cObj).Type().Name()))
|
||||
}
|
||||
return fn(cObj)
|
||||
}
|
||||
panic(fmt.Sprintf("This should never happen %#v", obj))
|
||||
return obj, nil
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ func runTest(t *testing.T, source interface{}) {
|
||||
name := reflect.TypeOf(source).Name()
|
||||
data, err := Encode(source)
|
||||
if err != nil {
|
||||
t.Errorf("%v: %v", name, err)
|
||||
t.Errorf("%v: %v (%#v)", name, err, source)
|
||||
return
|
||||
}
|
||||
obj2, err := Decode(data)
|
||||
@ -34,17 +34,17 @@ func runTest(t *testing.T, source interface{}) {
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(source, obj2) {
|
||||
t.Errorf("%v: wanted %#v, got %#v", name, source, obj2)
|
||||
t.Errorf("1: %v: wanted %#v, got %#v", name, source, obj2)
|
||||
return
|
||||
}
|
||||
obj3 := reflect.New(reflect.TypeOf(source).Elem()).Interface()
|
||||
err = DecodeInto(data, obj3)
|
||||
if err != nil {
|
||||
t.Errorf("%v: %v", name, err)
|
||||
t.Errorf("2: %v: %v", name, err)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(source, obj3) {
|
||||
t.Errorf("%v: wanted %#v, got %#v", name, source, obj3)
|
||||
t.Errorf("3: %v: wanted %#v, got %#v", name, source, obj3)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -84,7 +84,10 @@ func TestTypes(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNonPtr(t *testing.T) {
|
||||
obj := interface{}(Pod{Labels: map[string]string{"name": "foo"}})
|
||||
pod := Pod{
|
||||
Labels: map[string]string{"name": "foo"},
|
||||
}
|
||||
obj := interface{}(pod)
|
||||
data, err := Encode(obj)
|
||||
obj2, err2 := Decode(data)
|
||||
if err != nil || err2 != nil {
|
||||
@ -93,13 +96,16 @@ func TestNonPtr(t *testing.T) {
|
||||
if _, ok := obj2.(*Pod); !ok {
|
||||
t.Errorf("Got wrong type")
|
||||
}
|
||||
if !reflect.DeepEqual(obj2, &Pod{Labels: map[string]string{"name": "foo"}}) {
|
||||
t.Errorf("Something changed: %#v", obj2)
|
||||
if !reflect.DeepEqual(obj2, &pod) {
|
||||
t.Errorf("Expected:\n %#v,\n Got:\n %#v", &pod, obj2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPtr(t *testing.T) {
|
||||
obj := interface{}(&Pod{Labels: map[string]string{"name": "foo"}})
|
||||
pod := Pod{
|
||||
Labels: map[string]string{"name": "foo"},
|
||||
}
|
||||
obj := interface{}(&pod)
|
||||
data, err := Encode(obj)
|
||||
obj2, err2 := Decode(data)
|
||||
if err != nil || err2 != nil {
|
||||
@ -108,8 +114,8 @@ func TestPtr(t *testing.T) {
|
||||
if _, ok := obj2.(*Pod); !ok {
|
||||
t.Errorf("Got wrong type")
|
||||
}
|
||||
if !reflect.DeepEqual(obj2, &Pod{Labels: map[string]string{"name": "foo"}}) {
|
||||
t.Errorf("Something changed: %#v", obj2)
|
||||
if !reflect.DeepEqual(obj2, &pod) {
|
||||
t.Errorf("Expected:\n %#v,\n Got:\n %#v", &pod, obj2)
|
||||
}
|
||||
}
|
||||
|
||||
@ -122,8 +128,8 @@ func TestBadJSONRejection(t *testing.T) {
|
||||
if _, err1 := Decode(badJSONUnknownType); err1 == nil {
|
||||
t.Errorf("Did not reject despite use of unknown type: %s", badJSONUnknownType)
|
||||
}
|
||||
badJSONKindMismatch := []byte(`{"kind": "Pod"}`)
|
||||
/*badJSONKindMismatch := []byte(`{"kind": "Pod"}`)
|
||||
if err2 := DecodeInto(badJSONKindMismatch, &Minion{}); err2 == nil {
|
||||
t.Errorf("Kind is set but doesn't match the object type: %s", badJSONKindMismatch)
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
@ -189,6 +189,7 @@ type JSONBase struct {
|
||||
CreationTimestamp string `json:"creationTimestamp,omitempty" yaml:"creationTimestamp,omitempty"`
|
||||
SelfLink string `json:"selfLink,omitempty" yaml:"selfLink,omitempty"`
|
||||
ResourceVersion uint64 `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"`
|
||||
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
|
||||
}
|
||||
|
||||
// PodStatus represents a status of a pod.
|
||||
|
18
pkg/api/v1beta1/doc.go
Normal file
18
pkg/api/v1beta1/doc.go
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
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 v1beta1 is the v1beta1 version of the API
|
||||
package v1beta1
|
361
pkg/api/v1beta1/types.go
Normal file
361
pkg/api/v1beta1/types.go
Normal file
@ -0,0 +1,361 @@
|
||||
/*
|
||||
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 v1beta1
|
||||
|
||||
import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||
"github.com/fsouza/go-dockerclient"
|
||||
)
|
||||
|
||||
// Common string formats
|
||||
// ---------------------
|
||||
// Many fields in this API have formatting requirements. The commonly used
|
||||
// formats are defined here.
|
||||
//
|
||||
// C_IDENTIFIER: This is a string that conforms the definition of an "identifier"
|
||||
// in the C language. This is captured by the following regex:
|
||||
// [A-Za-z_][A-Za-z0-9_]*
|
||||
// This defines the format, but not the length restriction, which should be
|
||||
// specified at the definition of any field of this type.
|
||||
//
|
||||
// DNS_LABEL: This is a string, no more than 63 characters long, that conforms
|
||||
// to the definition of a "label" in RFCs 1035 and 1123. This is captured
|
||||
// by the following regex:
|
||||
// [a-z0-9]([-a-z0-9]*[a-z0-9])?
|
||||
//
|
||||
// DNS_SUBDOMAIN: This is a string, no more than 253 characters long, that conforms
|
||||
// to the definition of a "subdomain" in RFCs 1035 and 1123. This is captured
|
||||
// by the following regex:
|
||||
// [a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*
|
||||
// or more simply:
|
||||
// DNS_LABEL(\.DNS_LABEL)*
|
||||
|
||||
// ContainerManifest corresponds to the Container Manifest format, documented at:
|
||||
// https://developers.google.com/compute/docs/containers/container_vms#container_manifest
|
||||
// This is used as the representation of Kubernetes workloads.
|
||||
type ContainerManifest struct {
|
||||
// Required: This must be a supported version string, such as "v1beta1".
|
||||
Version string `yaml:"version" json:"version"`
|
||||
// Required: This must be a DNS_SUBDOMAIN.
|
||||
// TODO: ID on Manifest is deprecated and will be removed in the future.
|
||||
ID string `yaml:"id" json:"id"`
|
||||
Volumes []Volume `yaml:"volumes" json:"volumes"`
|
||||
Containers []Container `yaml:"containers" json:"containers"`
|
||||
}
|
||||
|
||||
// Volume represents a named volume in a pod that may be accessed by any containers in the pod.
|
||||
type Volume struct {
|
||||
// Required: This must be a DNS_LABEL. Each volume in a pod must have
|
||||
// a unique name.
|
||||
Name string `yaml:"name" json:"name"`
|
||||
// Source represents the location and type of a volume to mount.
|
||||
// This is optional for now. If not specified, the Volume is implied to be an EmptyDir.
|
||||
// This implied behavior is deprecated and will be removed in a future version.
|
||||
Source *VolumeSource `yaml:"source" json:"source"`
|
||||
}
|
||||
|
||||
type VolumeSource struct {
|
||||
// Only one of the following sources may be specified
|
||||
// HostDirectory represents a pre-existing directory on the host machine that is directly
|
||||
// exposed to the container. This is generally used for system agents or other privileged
|
||||
// things that are allowed to see the host machine. Most containers will NOT need this.
|
||||
// TODO(jonesdl) We need to restrict who can use host directory mounts and
|
||||
// who can/can not mount host directories as read/write.
|
||||
HostDirectory *HostDirectory `yaml:"hostDir" json:"hostDir"`
|
||||
// EmptyDirectory represents a temporary directory that shares a pod's lifetime.
|
||||
EmptyDirectory *EmptyDirectory `yaml:"emptyDir" json:"emptyDir"`
|
||||
}
|
||||
|
||||
// Bare host directory volume.
|
||||
type HostDirectory struct {
|
||||
Path string `yaml:"path" json:"path"`
|
||||
}
|
||||
|
||||
type EmptyDirectory struct{}
|
||||
|
||||
// Port represents a network port in a single container
|
||||
type Port struct {
|
||||
// Optional: If specified, this must be a DNS_LABEL. Each named port
|
||||
// in a pod must have a unique name.
|
||||
Name string `yaml:"name,omitempty" json:"name,omitempty"`
|
||||
// Optional: Defaults to ContainerPort. If specified, this must be a
|
||||
// valid port number, 0 < x < 65536.
|
||||
HostPort int `yaml:"hostPort,omitempty" json:"hostPort,omitempty"`
|
||||
// Required: This must be a valid port number, 0 < x < 65536.
|
||||
ContainerPort int `yaml:"containerPort" json:"containerPort"`
|
||||
// Optional: Defaults to "TCP".
|
||||
Protocol string `yaml:"protocol,omitempty" json:"protocol,omitempty"`
|
||||
// Optional: What host IP to bind the external port to.
|
||||
HostIP string `yaml:"hostIP,omitempty" json:"hostIP,omitempty"`
|
||||
}
|
||||
|
||||
// VolumeMount describes a mounting of a Volume within a container
|
||||
type VolumeMount struct {
|
||||
// Required: This must match the Name of a Volume [above].
|
||||
Name string `yaml:"name" json:"name"`
|
||||
// Optional: Defaults to false (read-write).
|
||||
ReadOnly bool `yaml:"readOnly,omitempty" json:"readOnly,omitempty"`
|
||||
// Required.
|
||||
// Exactly one of the following must be set. If both are set, prefer MountPath.
|
||||
// DEPRECATED: Path will be removed in a future version of the API.
|
||||
MountPath string `yaml:"mountPath,omitempty" json:"mountPath,omitempty"`
|
||||
Path string `yaml:"path,omitempty" json:"path,omitempty"`
|
||||
// One of: "LOCAL" (local volume) or "HOST" (external mount from the host). Default: LOCAL.
|
||||
// DEPRECATED: MountType will be removed in a future version of the API.
|
||||
MountType string `yaml:"mountType,omitempty" json:"mountType,omitempty"`
|
||||
}
|
||||
|
||||
// EnvVar represents an environment variable present in a Container
|
||||
type EnvVar struct {
|
||||
// Required: This must be a C_IDENTIFIER.
|
||||
// Exactly one of the following must be set. If both are set, prefer Name.
|
||||
// DEPRECATED: EnvVar.Key will be removed in a future version of the API.
|
||||
Name string `yaml:"name" json:"name"`
|
||||
Key string `yaml:"key,omitempty" json:"key,omitempty"`
|
||||
// Optional: defaults to "".
|
||||
Value string `yaml:"value,omitempty" json:"value,omitempty"`
|
||||
}
|
||||
|
||||
// HTTPGetProbe describes a liveness probe based on HTTP Get requests.
|
||||
type HTTPGetProbe struct {
|
||||
// Path to access on the http server
|
||||
Path string `yaml:"path,omitempty" json:"path,omitempty"`
|
||||
// Name or number of the port to access on the container
|
||||
Port string `yaml:"port,omitempty" json:"port,omitempty"`
|
||||
// Host name to connect to. Optional, default: "localhost"
|
||||
Host string `yaml:"host,omitempty" json:"host,omitempty"`
|
||||
}
|
||||
|
||||
// LivenessProbe describes a liveness probe to be examined to the container.
|
||||
type LivenessProbe struct {
|
||||
// Type of liveness probe. Current legal values "http"
|
||||
Type string `yaml:"type,omitempty" json:"type,omitempty"`
|
||||
// HTTPGetProbe parameters, required if Type == 'http'
|
||||
HTTPGet *HTTPGetProbe `yaml:"httpGet,omitempty" json:"httpGet,omitempty"`
|
||||
// Length of time before health checking is activated. In seconds.
|
||||
InitialDelaySeconds int64 `yaml:"initialDelaySeconds,omitempty" json:"initialDelaySeconds,omitempty"`
|
||||
}
|
||||
|
||||
// Container represents a single container that is expected to be run on the host.
|
||||
type Container struct {
|
||||
// Required: This must be a DNS_LABEL. Each container in a pod must
|
||||
// have a unique name.
|
||||
Name string `yaml:"name" json:"name"`
|
||||
// Required.
|
||||
Image string `yaml:"image" json:"image"`
|
||||
// Optional: Defaults to whatever is defined in the image.
|
||||
Command []string `yaml:"command,omitempty" json:"command,omitempty"`
|
||||
// Optional: Defaults to Docker's default.
|
||||
WorkingDir string `yaml:"workingDir,omitempty" json:"workingDir,omitempty"`
|
||||
Ports []Port `yaml:"ports,omitempty" json:"ports,omitempty"`
|
||||
Env []EnvVar `yaml:"env,omitempty" json:"env,omitempty"`
|
||||
// Optional: Defaults to unlimited.
|
||||
Memory int `yaml:"memory,omitempty" json:"memory,omitempty"`
|
||||
// Optional: Defaults to unlimited.
|
||||
CPU int `yaml:"cpu,omitempty" json:"cpu,omitempty"`
|
||||
VolumeMounts []VolumeMount `yaml:"volumeMounts,omitempty" json:"volumeMounts,omitempty"`
|
||||
LivenessProbe *LivenessProbe `yaml:"livenessProbe,omitempty" json:"livenessProbe,omitempty"`
|
||||
}
|
||||
|
||||
// Event is the representation of an event logged to etcd backends
|
||||
type Event struct {
|
||||
Event string `json:"event,omitempty"`
|
||||
Manifest *ContainerManifest `json:"manifest,omitempty"`
|
||||
Container *Container `json:"container,omitempty"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
// The below types are used by kube_client and api_server.
|
||||
|
||||
// JSONBase is shared by all objects sent to, or returned from the client
|
||||
type JSONBase struct {
|
||||
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
|
||||
ID string `json:"id,omitempty" yaml:"id,omitempty"`
|
||||
CreationTimestamp string `json:"creationTimestamp,omitempty" yaml:"creationTimestamp,omitempty"`
|
||||
SelfLink string `json:"selfLink,omitempty" yaml:"selfLink,omitempty"`
|
||||
ResourceVersion uint64 `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"`
|
||||
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
|
||||
}
|
||||
|
||||
// PodStatus represents a status of a pod.
|
||||
type PodStatus string
|
||||
|
||||
// These are the valid statuses of pods.
|
||||
const (
|
||||
PodRunning PodStatus = "Running"
|
||||
PodPending PodStatus = "Pending"
|
||||
PodStopped PodStatus = "Stopped"
|
||||
)
|
||||
|
||||
// PodInfo contains one entry for every container with available info.
|
||||
type PodInfo map[string]docker.Container
|
||||
|
||||
// PodState is the state of a pod, used as either input (desired state) or output (current state)
|
||||
type PodState struct {
|
||||
Manifest ContainerManifest `json:"manifest,omitempty" yaml:"manifest,omitempty"`
|
||||
Status PodStatus `json:"status,omitempty" yaml:"status,omitempty"`
|
||||
Host string `json:"host,omitempty" yaml:"host,omitempty"`
|
||||
HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty"`
|
||||
PodIP string `json:"podIP,omitempty" yaml:"podIP,omitempty"`
|
||||
|
||||
// The key of this map is the *name* of the container within the manifest; it has one
|
||||
// entry per container in the manifest. The value of this map is currently the output
|
||||
// of `docker inspect`. This output format is *not* final and should not be relied
|
||||
// upon.
|
||||
// TODO: Make real decisions about what our info should look like.
|
||||
Info PodInfo `json:"info,omitempty" yaml:"info,omitempty"`
|
||||
}
|
||||
|
||||
// PodList is a list of Pods.
|
||||
type PodList struct {
|
||||
JSONBase `json:",inline" yaml:",inline"`
|
||||
Items []Pod `json:"items" yaml:"items,omitempty"`
|
||||
}
|
||||
|
||||
// Pod is a collection of containers, used as either input (create, update) or as output (list, get)
|
||||
type Pod struct {
|
||||
JSONBase `json:",inline" yaml:",inline"`
|
||||
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
|
||||
DesiredState PodState `json:"desiredState,omitempty" yaml:"desiredState,omitempty"`
|
||||
CurrentState PodState `json:"currentState,omitempty" yaml:"currentState,omitempty"`
|
||||
}
|
||||
|
||||
// ReplicationControllerState is the state of a replication controller, either input (create, update) or as output (list, get)
|
||||
type ReplicationControllerState struct {
|
||||
Replicas int `json:"replicas" yaml:"replicas"`
|
||||
ReplicaSelector map[string]string `json:"replicaSelector,omitempty" yaml:"replicaSelector,omitempty"`
|
||||
PodTemplate PodTemplate `json:"podTemplate,omitempty" yaml:"podTemplate,omitempty"`
|
||||
}
|
||||
|
||||
// ReplicationControllerList is a collection of replication controllers.
|
||||
type ReplicationControllerList struct {
|
||||
JSONBase `json:",inline" yaml:",inline"`
|
||||
Items []ReplicationController `json:"items,omitempty" yaml:"items,omitempty"`
|
||||
}
|
||||
|
||||
// ReplicationController represents the configuration of a replication controller
|
||||
type ReplicationController struct {
|
||||
JSONBase `json:",inline" yaml:",inline"`
|
||||
DesiredState ReplicationControllerState `json:"desiredState,omitempty" yaml:"desiredState,omitempty"`
|
||||
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
|
||||
}
|
||||
|
||||
// PodTemplate holds the information used for creating pods
|
||||
type PodTemplate struct {
|
||||
DesiredState PodState `json:"desiredState,omitempty" yaml:"desiredState,omitempty"`
|
||||
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
|
||||
}
|
||||
|
||||
// ServiceList holds a list of services
|
||||
type ServiceList struct {
|
||||
JSONBase `json:",inline" yaml:",inline"`
|
||||
Items []Service `json:"items" yaml:"items"`
|
||||
}
|
||||
|
||||
// Service is a named abstraction of software service (for example, mysql) consisting of local port
|
||||
// (for example 3306) that the proxy listens on, and the selector that determines which pods
|
||||
// will answer requests sent through the proxy.
|
||||
type Service struct {
|
||||
JSONBase `json:",inline" yaml:",inline"`
|
||||
Port int `json:"port,omitempty" yaml:"port,omitempty"`
|
||||
|
||||
// This service's labels.
|
||||
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
|
||||
|
||||
// This service will route traffic to pods having labels matching this selector.
|
||||
Selector map[string]string `json:"selector,omitempty" yaml:"selector,omitempty"`
|
||||
CreateExternalLoadBalancer bool `json:"createExternalLoadBalancer,omitempty" yaml:"createExternalLoadBalancer,omitempty"`
|
||||
|
||||
// ContainerPort is the name of the port on the container to direct traffic to.
|
||||
// Optional, if unspecified use the first port on the container.
|
||||
ContainerPort util.IntOrString `json:"containerPort,omitempty" yaml:"containerPort,omitempty"`
|
||||
}
|
||||
|
||||
// Endpoints is a collection of endpoints that implement the actual service, for example:
|
||||
// Name: "mysql", Endpoints: ["10.10.1.1:1909", "10.10.2.2:8834"]
|
||||
type Endpoints struct {
|
||||
Name string
|
||||
Endpoints []string
|
||||
}
|
||||
|
||||
// Minion is a worker node in Kubernetenes.
|
||||
// The name of the minion according to etcd is in JSONBase.ID.
|
||||
type Minion struct {
|
||||
JSONBase `json:",inline" yaml:",inline"`
|
||||
// Queried from cloud provider, if available.
|
||||
HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty"`
|
||||
}
|
||||
|
||||
// MinionList is a list of minions.
|
||||
type MinionList struct {
|
||||
JSONBase `json:",inline" yaml:",inline"`
|
||||
Items []Minion `json:"minions,omitempty" yaml:"minions,omitempty"`
|
||||
}
|
||||
|
||||
// Status is a return value for calls that don't return other objects.
|
||||
// Arguably, this could go in apiserver, but I'm including it here so clients needn't
|
||||
// import both.
|
||||
type Status struct {
|
||||
JSONBase `json:",inline" yaml:",inline"`
|
||||
// One of: "success", "failure", "working" (for operations not yet completed)
|
||||
// TODO: if "working", include an operation identifier so final status can be
|
||||
// checked.
|
||||
Status string `json:"status,omitempty" yaml:"status,omitempty"`
|
||||
// Details about the status. May be an error description or an
|
||||
// operation number for later polling.
|
||||
Details string `json:"details,omitempty" yaml:"details,omitempty"`
|
||||
// Suggested HTTP return code for this status, 0 if not set.
|
||||
Code int `json:"code,omitempty" yaml:"code,omitempty"`
|
||||
}
|
||||
|
||||
// Values of Status.Status
|
||||
const (
|
||||
StatusSuccess = "success"
|
||||
StatusFailure = "failure"
|
||||
StatusWorking = "working"
|
||||
)
|
||||
|
||||
// ServerOp is an operation delivered to API clients.
|
||||
type ServerOp struct {
|
||||
JSONBase `yaml:",inline" json:",inline"`
|
||||
}
|
||||
|
||||
// ServerOpList is a list of operations, as delivered to API clients.
|
||||
type ServerOpList struct {
|
||||
JSONBase `yaml:",inline" json:",inline"`
|
||||
Items []ServerOp `yaml:"items,omitempty" json:"items,omitempty"`
|
||||
}
|
||||
|
||||
// WatchEvent objects are streamed from the api server in response to a watch request.
|
||||
type WatchEvent struct {
|
||||
// The type of the watch event; added, modified, or deleted.
|
||||
Type watch.EventType
|
||||
|
||||
// For added or modified objects, this is the new object; for deleted objects,
|
||||
// it's the state of the object immediately prior to its deletion.
|
||||
Object APIObject
|
||||
}
|
||||
|
||||
// APIObject has appropriate encoder and decoder functions, such that on the wire, it's
|
||||
// stored as a []byte, but in memory, the contained object is accessable as an interface{}
|
||||
// via the Get() function. Only objects having a JSONBase may be stored via APIObject.
|
||||
// The purpose of this is to allow an API object of type known only at runtime to be
|
||||
// embedded within other API objects.
|
||||
type APIObject struct {
|
||||
Object interface{}
|
||||
}
|
@ -21,6 +21,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
@ -36,8 +37,17 @@ import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||
)
|
||||
|
||||
func convert(obj interface{}) (interface{}, error) {
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
api.AddKnownTypes(Simple{}, SimpleList{})
|
||||
api.AddKnownTypes("", Simple{}, SimpleList{})
|
||||
api.AddKnownTypes("v1beta1", Simple{}, SimpleList{})
|
||||
api.AddExternalConversion("Simple", convert)
|
||||
api.AddInternalConversion("Simple", convert)
|
||||
api.AddExternalConversion("SimpleList", convert)
|
||||
api.AddInternalConversion("SimpleList", convert)
|
||||
}
|
||||
|
||||
// TODO: This doesn't reduce typing enough to make it worth the less readable errors. Remove.
|
||||
@ -154,6 +164,7 @@ func (storage *SimpleRESTStorage) WatchSingle(id string) (watch.Interface, error
|
||||
func extractBody(response *http.Response, object interface{}) (string, error) {
|
||||
defer response.Body.Close()
|
||||
body, err := ioutil.ReadAll(response.Body)
|
||||
log.Printf("FOO: %s", body)
|
||||
if err != nil {
|
||||
return string(body), err
|
||||
}
|
||||
@ -198,7 +209,8 @@ func TestNonEmptyList(t *testing.T) {
|
||||
simpleStorage := SimpleRESTStorage{
|
||||
list: []Simple{
|
||||
{
|
||||
Name: "foo",
|
||||
JSONBase: api.JSONBase{Kind: "Simple"},
|
||||
Name: "foo",
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -395,7 +407,9 @@ func TestCreate(t *testing.T) {
|
||||
server := httptest.NewServer(handler)
|
||||
client := http.Client{}
|
||||
|
||||
simple := Simple{Name: "foo"}
|
||||
simple := Simple{
|
||||
Name: "foo",
|
||||
}
|
||||
data, _ := api.Encode(simple)
|
||||
request, err := http.NewRequest("POST", server.URL+"/prefix/version/foo", bytes.NewBuffer(data))
|
||||
expectNoError(t, err)
|
||||
@ -461,7 +475,9 @@ func TestSyncCreate(t *testing.T) {
|
||||
server := httptest.NewServer(handler)
|
||||
client := http.Client{}
|
||||
|
||||
simple := Simple{Name: "foo"}
|
||||
simple := Simple{
|
||||
Name: "foo",
|
||||
}
|
||||
data, _ := api.Encode(simple)
|
||||
request, err := http.NewRequest("POST", server.URL+"/prefix/version/foo?sync=true", bytes.NewBuffer(data))
|
||||
expectNoError(t, err)
|
||||
@ -530,8 +546,12 @@ func TestOpGet(t *testing.T) {
|
||||
server := httptest.NewServer(handler)
|
||||
client := http.Client{}
|
||||
|
||||
simple := Simple{Name: "foo"}
|
||||
data, _ := api.Encode(simple)
|
||||
simple := Simple{
|
||||
Name: "foo",
|
||||
}
|
||||
data, err := api.Encode(simple)
|
||||
t.Log(string(data))
|
||||
expectNoError(t, err)
|
||||
request, err := http.NewRequest("POST", server.URL+"/prefix/version/foo", bytes.NewBuffer(data))
|
||||
expectNoError(t, err)
|
||||
response, err := client.Do(request)
|
||||
|
@ -175,9 +175,7 @@ func TestGetController(t *testing.T) {
|
||||
Response: Response{
|
||||
StatusCode: 200,
|
||||
Body: api.ReplicationController{
|
||||
JSONBase: api.JSONBase{
|
||||
ID: "foo",
|
||||
},
|
||||
JSONBase: api.JSONBase{ID: "foo"},
|
||||
DesiredState: api.ReplicationControllerState{
|
||||
Replicas: 2,
|
||||
},
|
||||
@ -194,18 +192,14 @@ func TestGetController(t *testing.T) {
|
||||
|
||||
func TestUpdateController(t *testing.T) {
|
||||
requestController := api.ReplicationController{
|
||||
JSONBase: api.JSONBase{
|
||||
ID: "foo",
|
||||
},
|
||||
JSONBase: api.JSONBase{ID: "foo"},
|
||||
}
|
||||
c := &testClient{
|
||||
Request: testRequest{Method: "PUT", Path: "/replicationControllers/foo"},
|
||||
Response: Response{
|
||||
StatusCode: 200,
|
||||
Body: api.ReplicationController{
|
||||
JSONBase: api.JSONBase{
|
||||
ID: "foo",
|
||||
},
|
||||
JSONBase: api.JSONBase{ID: "foo"},
|
||||
DesiredState: api.ReplicationControllerState{
|
||||
Replicas: 2,
|
||||
},
|
||||
@ -231,18 +225,14 @@ func TestDeleteController(t *testing.T) {
|
||||
|
||||
func TestCreateController(t *testing.T) {
|
||||
requestController := api.ReplicationController{
|
||||
JSONBase: api.JSONBase{
|
||||
ID: "foo",
|
||||
},
|
||||
JSONBase: api.JSONBase{ID: "foo"},
|
||||
}
|
||||
c := &testClient{
|
||||
Request: testRequest{Method: "POST", Path: "/replicationControllers", Body: requestController},
|
||||
Response: Response{
|
||||
StatusCode: 200,
|
||||
Body: api.ReplicationController{
|
||||
JSONBase: api.JSONBase{
|
||||
ID: "foo",
|
||||
},
|
||||
JSONBase: api.JSONBase{ID: "foo"},
|
||||
DesiredState: api.ReplicationControllerState{
|
||||
Replicas: 2,
|
||||
},
|
||||
|
@ -99,7 +99,7 @@ func validateSyncReplication(t *testing.T, fakePodControl *FakePodControl, expec
|
||||
}
|
||||
|
||||
func TestSyncReplicationControllerDoesNothing(t *testing.T) {
|
||||
body, _ := json.Marshal(makePodList(2))
|
||||
body, _ := api.Encode(makePodList(2))
|
||||
fakeHandler := util.FakeHandler{
|
||||
StatusCode: 200,
|
||||
ResponseBody: string(body),
|
||||
@ -119,7 +119,7 @@ func TestSyncReplicationControllerDoesNothing(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSyncReplicationControllerDeletes(t *testing.T) {
|
||||
body, _ := json.Marshal(makePodList(2))
|
||||
body, _ := api.Encode(makePodList(2))
|
||||
fakeHandler := util.FakeHandler{
|
||||
StatusCode: 200,
|
||||
ResponseBody: string(body),
|
||||
@ -139,7 +139,7 @@ func TestSyncReplicationControllerDeletes(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSyncReplicationControllerCreates(t *testing.T) {
|
||||
body := "{ \"items\": [] }"
|
||||
body, _ := api.Encode(makePodList(0))
|
||||
fakeHandler := util.FakeHandler{
|
||||
StatusCode: 200,
|
||||
ResponseBody: string(body),
|
||||
@ -159,7 +159,7 @@ func TestSyncReplicationControllerCreates(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCreateReplica(t *testing.T) {
|
||||
body := "{}"
|
||||
body, _ := api.Encode(api.Pod{})
|
||||
fakeHandler := util.FakeHandler{
|
||||
StatusCode: 200,
|
||||
ResponseBody: string(body),
|
||||
@ -172,6 +172,9 @@ func TestCreateReplica(t *testing.T) {
|
||||
}
|
||||
|
||||
controllerSpec := api.ReplicationController{
|
||||
JSONBase: api.JSONBase{
|
||||
Kind: "ReplicationController",
|
||||
},
|
||||
DesiredState: api.ReplicationControllerState{
|
||||
PodTemplate: api.PodTemplate{
|
||||
DesiredState: api.PodState{
|
||||
@ -195,7 +198,8 @@ func TestCreateReplica(t *testing.T) {
|
||||
|
||||
expectedPod := api.Pod{
|
||||
JSONBase: api.JSONBase{
|
||||
Kind: "Pod",
|
||||
Kind: "Pod",
|
||||
APIVersion: "v1beta1",
|
||||
},
|
||||
Labels: controllerSpec.DesiredState.PodTemplate.Labels,
|
||||
DesiredState: controllerSpec.DesiredState.PodTemplate.DesiredState,
|
||||
@ -207,12 +211,12 @@ func TestCreateReplica(t *testing.T) {
|
||||
}
|
||||
if !reflect.DeepEqual(expectedPod, actualPod) {
|
||||
t.Logf("Body: %s", fakeHandler.RequestBody)
|
||||
t.Errorf("Unexpected mismatch. Expected %#v, Got: %#v", expectedPod, actualPod)
|
||||
t.Errorf("Unexpected mismatch. Expected\n %#v,\n Got:\n %#v", expectedPod, actualPod)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleWatchResponseNotSet(t *testing.T) {
|
||||
body, _ := json.Marshal(makePodList(2))
|
||||
body, _ := api.Encode(makePodList(2))
|
||||
fakeHandler := util.FakeHandler{
|
||||
StatusCode: 200,
|
||||
ResponseBody: string(body),
|
||||
@ -233,7 +237,7 @@ func TestHandleWatchResponseNotSet(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHandleWatchResponseNoNode(t *testing.T) {
|
||||
body, _ := json.Marshal(makePodList(2))
|
||||
body, _ := api.Encode(makePodList(2))
|
||||
fakeHandler := util.FakeHandler{
|
||||
StatusCode: 200,
|
||||
ResponseBody: string(body),
|
||||
@ -254,7 +258,7 @@ func TestHandleWatchResponseNoNode(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHandleWatchResponseBadData(t *testing.T) {
|
||||
body, _ := json.Marshal(makePodList(2))
|
||||
body, _ := api.Encode(makePodList(2))
|
||||
fakeHandler := util.FakeHandler{
|
||||
StatusCode: 200,
|
||||
ResponseBody: string(body),
|
||||
@ -278,7 +282,7 @@ func TestHandleWatchResponseBadData(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHandleWatchResponse(t *testing.T) {
|
||||
body, _ := json.Marshal(makePodList(2))
|
||||
body, _ := api.Encode(makePodList(2))
|
||||
fakeHandler := util.FakeHandler{
|
||||
StatusCode: 200,
|
||||
ResponseBody: string(body),
|
||||
@ -293,6 +297,7 @@ func TestHandleWatchResponse(t *testing.T) {
|
||||
|
||||
controller := makeReplicationController(2)
|
||||
|
||||
// TODO: fixme when etcd uses Encode/Decode
|
||||
data, err := json.Marshal(controller)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
@ -312,7 +317,7 @@ func TestHandleWatchResponse(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHandleWatchResponseDelete(t *testing.T) {
|
||||
body, _ := json.Marshal(makePodList(2))
|
||||
body, _ := api.Encode(makePodList(2))
|
||||
fakeHandler := util.FakeHandler{
|
||||
StatusCode: 200,
|
||||
ResponseBody: string(body),
|
||||
@ -327,6 +332,7 @@ func TestHandleWatchResponseDelete(t *testing.T) {
|
||||
|
||||
controller := makeReplicationController(2)
|
||||
|
||||
// TODO: fixme when etcd writing uses api.Encode
|
||||
data, err := json.Marshal(controller)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
@ -347,6 +353,7 @@ func TestHandleWatchResponseDelete(t *testing.T) {
|
||||
|
||||
func TestSyncronize(t *testing.T) {
|
||||
controllerSpec1 := api.ReplicationController{
|
||||
JSONBase: api.JSONBase{APIVersion: "v1beta1"},
|
||||
DesiredState: api.ReplicationControllerState{
|
||||
Replicas: 4,
|
||||
PodTemplate: api.PodTemplate{
|
||||
@ -367,6 +374,7 @@ func TestSyncronize(t *testing.T) {
|
||||
},
|
||||
}
|
||||
controllerSpec2 := api.ReplicationController{
|
||||
JSONBase: api.JSONBase{APIVersion: "v1beta1"},
|
||||
DesiredState: api.ReplicationControllerState{
|
||||
Replicas: 3,
|
||||
PodTemplate: api.PodTemplate{
|
||||
@ -405,7 +413,7 @@ func TestSyncronize(t *testing.T) {
|
||||
|
||||
fakeHandler := util.FakeHandler{
|
||||
StatusCode: 200,
|
||||
ResponseBody: "{}",
|
||||
ResponseBody: "{\"apiVersion\": \"v1beta1\", \"kind\": \"PodList\"}",
|
||||
T: t,
|
||||
}
|
||||
testServer := httptest.NewTLSServer(&fakeHandler)
|
||||
|
@ -34,7 +34,7 @@ func DoParseTest(t *testing.T, storage string, obj interface{}) {
|
||||
jsonData, _ := api.Encode(obj)
|
||||
yamlData, _ := yaml.Marshal(obj)
|
||||
t.Logf("Intermediate yaml:\n%v\n", string(yamlData))
|
||||
|
||||
t.Logf("Intermediate json:\n%v\n", string(jsonData))
|
||||
jsonGot, jsonErr := ToWireFormat(jsonData, storage)
|
||||
yamlGot, yamlErr := ToWireFormat(yamlData, storage)
|
||||
|
||||
@ -56,7 +56,7 @@ func DoParseTest(t *testing.T, storage string, obj interface{}) {
|
||||
|
||||
func TestParsePod(t *testing.T) {
|
||||
DoParseTest(t, "pods", api.Pod{
|
||||
JSONBase: api.JSONBase{ID: "test pod"},
|
||||
JSONBase: api.JSONBase{APIVersion: "v1beta1", ID: "test pod", Kind: "Pod"},
|
||||
DesiredState: api.PodState{
|
||||
Manifest: api.ContainerManifest{
|
||||
ID: "My manifest",
|
||||
@ -73,7 +73,7 @@ func TestParsePod(t *testing.T) {
|
||||
|
||||
func TestParseService(t *testing.T) {
|
||||
DoParseTest(t, "services", api.Service{
|
||||
JSONBase: api.JSONBase{ID: "my service"},
|
||||
JSONBase: api.JSONBase{APIVersion: "v1beta1", ID: "my service", Kind: "Service"},
|
||||
Port: 8080,
|
||||
Labels: map[string]string{
|
||||
"area": "staging",
|
||||
@ -86,6 +86,7 @@ func TestParseService(t *testing.T) {
|
||||
|
||||
func TestParseController(t *testing.T) {
|
||||
DoParseTest(t, "replicationControllers", api.ReplicationController{
|
||||
JSONBase: api.JSONBase{APIVersion: "v1beta1", ID: "my controller", Kind: "ReplicationController"},
|
||||
DesiredState: api.ReplicationControllerState{
|
||||
Replicas: 9001,
|
||||
PodTemplate: api.PodTemplate{
|
||||
|
@ -32,7 +32,8 @@ func makePodList(count int) api.PodList {
|
||||
for i := 0; i < count; i++ {
|
||||
pods = append(pods, api.Pod{
|
||||
JSONBase: api.JSONBase{
|
||||
ID: fmt.Sprintf("pod%d", i),
|
||||
ID: fmt.Sprintf("pod%d", i),
|
||||
APIVersion: "v1beta1",
|
||||
},
|
||||
DesiredState: api.PodState{
|
||||
Manifest: api.ContainerManifest{
|
||||
@ -53,7 +54,8 @@ func makePodList(count int) api.PodList {
|
||||
})
|
||||
}
|
||||
return api.PodList{
|
||||
Items: pods,
|
||||
JSONBase: api.JSONBase{APIVersion: "v1beta1", Kind: "PodList"},
|
||||
Items: pods,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ import (
|
||||
"io"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||
@ -39,18 +40,28 @@ func TestDecoder(t *testing.T) {
|
||||
}
|
||||
}()
|
||||
|
||||
action, got, err := decoder.Decode()
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
}
|
||||
if e, a := watch.Added, action; e != a {
|
||||
t.Errorf("Expected %v, got %v", e, a)
|
||||
}
|
||||
if e, a := expect, got; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Expected %v, got %v", e, a)
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
action, got, err := decoder.Decode()
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
}
|
||||
if e, a := watch.Added, action; e != a {
|
||||
t.Errorf("Expected %v, got %v", e, a)
|
||||
}
|
||||
if e, a := expect, got; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Expected %v, got %v", e, a)
|
||||
}
|
||||
close(done)
|
||||
}()
|
||||
select {
|
||||
case <-done:
|
||||
break
|
||||
case <-time.After(10 * time.Second):
|
||||
t.Error("Timeout")
|
||||
}
|
||||
|
||||
done := make(chan struct{})
|
||||
done = make(chan struct{})
|
||||
|
||||
go func() {
|
||||
_, _, err := decoder.Decode()
|
||||
@ -62,7 +73,12 @@ func TestDecoder(t *testing.T) {
|
||||
|
||||
decoder.Close()
|
||||
|
||||
<-done
|
||||
select {
|
||||
case <-done:
|
||||
break
|
||||
case <-time.After(10 * time.Second):
|
||||
t.Error("Timeout")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecoder_SourceClose(t *testing.T) {
|
||||
@ -81,5 +97,10 @@ func TestDecoder_SourceClose(t *testing.T) {
|
||||
|
||||
in.Close()
|
||||
|
||||
<-done
|
||||
select {
|
||||
case <-done:
|
||||
break
|
||||
case <-time.After(10 * time.Second):
|
||||
t.Error("Timeout")
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user