kubernetes/pkg/api/helper.go
Daniel Smith b3cc696486 All types stored in etcd are now API objects.
This means I made an api.ContainerManifestList, and added a JSONBase to
endpoints (and changed Name -> JSONBase.ID).
2014-07-28 11:27:36 -07:00

939 lines
25 KiB
Go

/*
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 api
import (
"encoding/json"
"fmt"
"reflect"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
"gopkg.in/v1/yaml"
)
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("",
PodList{},
Pod{},
ReplicationControllerList{},
ReplicationController{},
ServiceList{},
Service{},
MinionList{},
Minion{},
Status{},
ServerOpList{},
ServerOp{},
ContainerManifestList{},
Endpoints{},
)
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(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) {
_, jsonBase, err := nameAndJSONBase(obj)
return jsonBase, err
}
// FindJSONBaseRO takes an arbitary api type, return a copy of its JSONBase field.
// obj may be a pointer to an api type, or a non-pointer struct api type.
func FindJSONBaseRO(obj interface{}) (JSONBase, error) {
v := reflect.ValueOf(obj)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
if v.Kind() != reflect.Struct {
return JSONBase{}, fmt.Errorf("expected struct, but got %v (%#v)", v.Type().Name(), v.Interface())
}
jsonBase := v.FieldByName("JSONBase")
if !jsonBase.IsValid() {
return JSONBase{}, fmt.Errorf("struct %v lacks embedded JSON type", v.Type().Name())
}
return jsonBase.Interface().(JSONBase), nil
}
// EncodeOrDie is a version of Encode which will panic instead of returning an error. For tests.
func EncodeOrDie(obj interface{}) string {
bytes, err := Encode(obj)
if err != nil {
panic(err)
}
return string(bytes)
}
// Encode turns the given api object into an appropriate JSON string.
// Will return an error if the object doesn't have an embedded JSONBase.
// Obj may be a pointer to a struct, or a struct. If a struct, a copy
// will be made so that the object's Kind field can be set. If a pointer,
// we change the Kind field, marshal, and then set the kind field back to
// "". Having to keep track of the kind field makes tests very annoying,
// so the rule is it's set only in wire format (json), not when in native
// format.
func Encode(obj interface{}) (data []byte, err error) {
obj = checkPtr(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
}
func checkPtr(obj interface{}) interface{} {
v := reflect.ValueOf(obj)
if v.Kind() == reflect.Ptr {
return obj
}
v2 := reflect.New(v.Type())
v2.Elem().Set(v)
return v2.Interface()
}
func prepareEncode(obj interface{}) (*JSONBase, error) {
name, jsonBase, err := nameAndJSONBase(obj)
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 it's not in known versions", jsonBase.APIVersion, obj)
}
if _, contains := knownTypes[name]; !contains {
return nil, fmt.Errorf("struct %s won't be unmarshalable because it's not in knownTypes", name)
}
jsonBase.Kind = name
return jsonBase, nil
}
// Returns the name of the type (sans pointer), and its kind field. Takes pointer-to-struct..
func nameAndJSONBase(obj interface{}) (string, *JSONBase, error) {
v := reflect.ValueOf(obj)
if v.Kind() != reflect.Ptr {
return "", nil, fmt.Errorf("expected pointer, but got %v", v.Type().Name())
}
v = v.Elem()
name := v.Type().Name()
if v.Kind() != reflect.Struct {
return "", nil, fmt.Errorf("expected struct, but got %v: %v (%#v)", v.Kind(), v.Type().Name(), v.Interface())
}
jsonBase := v.FieldByName("JSONBase")
if !jsonBase.IsValid() {
return "", nil, fmt.Errorf("struct %v lacks embedded JSON type", name)
}
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"`
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 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
}
// Don't leave these set. Track type with go's type.
jsonBase.Kind = ""
return obj, nil
}
// DecodeInto parses a JSON string and stores it in obj. Returns an 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 {
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
}
if jsonBase.Kind != "" && jsonBase.Kind != name {
return fmt.Errorf("data had kind %v, but passed object was of type %v", jsonBase.Kind, name)
}
// Don't leave these set. Track type with go's type.
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
}