Merge pull request #23847 from XiaoningDing/federation-apiobject-cluster

Automatic merge from submit-queue

Federation apiobject cluster

add federation api group
add cluster api object and registry
~~generate cluster client~~ moved to #24117
update scripts to generate files for /federation

#19313 #23653 #23554
@nikhiljindal  @quinton-hoole, @deepak-vij, @XiaoningDing, @alfred-huangjian @mfanjie @huangyuqi @colhom
This commit is contained in:
k8s-merge-robot 2016-04-27 00:26:22 -07:00
commit b7e4672db9
33 changed files with 8807 additions and 1 deletions

View File

@ -49,6 +49,8 @@ func main() {
"k8s.io/kubernetes/pkg/apis/extensions/v1beta1",
"k8s.io/kubernetes/pkg/apis/metrics",
"k8s.io/kubernetes/pkg/apis/metrics/v1alpha1",
"k8s.io/kubernetes/federation/apis/federation",
"k8s.io/kubernetes/federation/apis/federation/v1alpha1",
"k8s.io/kubernetes/pkg/conversion",
"k8s.io/kubernetes/pkg/runtime",
}

View File

@ -49,6 +49,8 @@ func main() {
"k8s.io/kubernetes/pkg/apis/extensions/v1beta1",
"k8s.io/kubernetes/pkg/apis/metrics",
"k8s.io/kubernetes/pkg/apis/metrics/v1alpha1",
"k8s.io/kubernetes/federation/apis/federation",
"k8s.io/kubernetes/federation/apis/federation/v1alpha1",
}
if err := arguments.Execute(

View File

@ -70,6 +70,7 @@ func New() *Generator {
`k8s.io/kubernetes/pkg/apis/autoscaling/v1`,
`k8s.io/kubernetes/pkg/apis/batch/v1`,
`k8s.io/kubernetes/pkg/apis/apps/v1alpha1`,
`k8s.io/kubernetes/federation/apis/federation/v1alpha1`,
}, ","),
DropEmbeddedFields: "k8s.io/kubernetes/pkg/api/unversioned.TypeMeta",
}

View File

@ -0,0 +1,158 @@
// +build !ignore_autogenerated
/*
Copyright 2016 The Kubernetes Authors 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.
*/
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
package federation
import (
api "k8s.io/kubernetes/pkg/api"
resource "k8s.io/kubernetes/pkg/api/resource"
unversioned "k8s.io/kubernetes/pkg/api/unversioned"
conversion "k8s.io/kubernetes/pkg/conversion"
)
func init() {
if err := api.Scheme.AddGeneratedDeepCopyFuncs(
DeepCopy_federation_Cluster,
DeepCopy_federation_ClusterCondition,
DeepCopy_federation_ClusterList,
DeepCopy_federation_ClusterMeta,
DeepCopy_federation_ClusterSpec,
DeepCopy_federation_ClusterStatus,
); err != nil {
// if one of the deep copy functions is malformed, detect it immediately.
panic(err)
}
}
func DeepCopy_federation_Cluster(in Cluster, out *Cluster, c *conversion.Cloner) error {
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
return err
}
if err := api.DeepCopy_api_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil {
return err
}
if err := DeepCopy_federation_ClusterSpec(in.Spec, &out.Spec, c); err != nil {
return err
}
if err := DeepCopy_federation_ClusterStatus(in.Status, &out.Status, c); err != nil {
return err
}
return nil
}
func DeepCopy_federation_ClusterCondition(in ClusterCondition, out *ClusterCondition, c *conversion.Cloner) error {
out.Type = in.Type
out.Status = in.Status
if err := unversioned.DeepCopy_unversioned_Time(in.LastProbeTime, &out.LastProbeTime, c); err != nil {
return err
}
if err := unversioned.DeepCopy_unversioned_Time(in.LastTransitionTime, &out.LastTransitionTime, c); err != nil {
return err
}
out.Reason = in.Reason
out.Message = in.Message
return nil
}
func DeepCopy_federation_ClusterList(in ClusterList, out *ClusterList, c *conversion.Cloner) error {
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
return err
}
if err := unversioned.DeepCopy_unversioned_ListMeta(in.ListMeta, &out.ListMeta, c); err != nil {
return err
}
if in.Items != nil {
in, out := in.Items, &out.Items
*out = make([]Cluster, len(in))
for i := range in {
if err := DeepCopy_federation_Cluster(in[i], &(*out)[i], c); err != nil {
return err
}
}
} else {
out.Items = nil
}
return nil
}
func DeepCopy_federation_ClusterMeta(in ClusterMeta, out *ClusterMeta, c *conversion.Cloner) error {
out.Version = in.Version
return nil
}
func DeepCopy_federation_ClusterSpec(in ClusterSpec, out *ClusterSpec, c *conversion.Cloner) error {
if in.ServerAddressByClientCIDRs != nil {
in, out := in.ServerAddressByClientCIDRs, &out.ServerAddressByClientCIDRs
*out = make([]unversioned.ServerAddressByClientCIDR, len(in))
for i := range in {
if err := unversioned.DeepCopy_unversioned_ServerAddressByClientCIDR(in[i], &(*out)[i], c); err != nil {
return err
}
}
} else {
out.ServerAddressByClientCIDRs = nil
}
out.Credential = in.Credential
return nil
}
func DeepCopy_federation_ClusterStatus(in ClusterStatus, out *ClusterStatus, c *conversion.Cloner) error {
if in.Conditions != nil {
in, out := in.Conditions, &out.Conditions
*out = make([]ClusterCondition, len(in))
for i := range in {
if err := DeepCopy_federation_ClusterCondition(in[i], &(*out)[i], c); err != nil {
return err
}
}
} else {
out.Conditions = nil
}
if in.Capacity != nil {
in, out := in.Capacity, &out.Capacity
*out = make(api.ResourceList)
for key, val := range in {
newVal := new(resource.Quantity)
if err := resource.DeepCopy_resource_Quantity(val, newVal, c); err != nil {
return err
}
(*out)[key] = *newVal
}
} else {
out.Capacity = nil
}
if in.Allocatable != nil {
in, out := in.Allocatable, &out.Allocatable
*out = make(api.ResourceList)
for key, val := range in {
newVal := new(resource.Quantity)
if err := resource.DeepCopy_resource_Quantity(val, newVal, c); err != nil {
return err
}
(*out)[key] = *newVal
}
} else {
out.Allocatable = nil
}
if err := DeepCopy_federation_ClusterMeta(in.ClusterMeta, &out.ClusterMeta, c); err != nil {
return err
}
return nil
}

View File

@ -0,0 +1,129 @@
/*
Copyright 2016 The Kubernetes Authors 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 install
import (
"fmt"
"github.com/golang/glog"
"k8s.io/kubernetes/federation/apis/federation"
"k8s.io/kubernetes/federation/apis/federation/v1alpha1"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apimachinery"
"k8s.io/kubernetes/pkg/apimachinery/registered"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/sets"
)
const importPrefix = "k8s.io/kubernetes/federation/apis/federation"
var accessor = meta.NewAccessor()
// availableVersions lists all known external versions for this group from most preferred to least preferred
var availableVersions = []unversioned.GroupVersion{v1alpha1.SchemeGroupVersion}
func init() {
registered.RegisterVersions(availableVersions)
externalVersions := []unversioned.GroupVersion{}
for _, v := range availableVersions {
if registered.IsAllowedVersion(v) {
externalVersions = append(externalVersions, v)
}
}
if len(externalVersions) == 0 {
glog.V(4).Infof("No version is registered for group %v", federation.GroupName)
return
}
if err := registered.EnableVersions(externalVersions...); err != nil {
glog.V(4).Infof("%v", err)
return
}
if err := enableVersions(externalVersions); err != nil {
glog.V(4).Infof("%v", err)
return
}
}
// TODO: enableVersions should be centralized rather than spread in each API
// group.
// We can combine registered.RegisterVersions, registered.EnableVersions and
// registered.RegisterGroup once we have moved enableVersions there.
func enableVersions(externalVersions []unversioned.GroupVersion) error {
addVersionsToScheme(externalVersions...)
preferredExternalVersion := externalVersions[0]
groupMeta := apimachinery.GroupMeta{
GroupVersion: preferredExternalVersion,
GroupVersions: externalVersions,
RESTMapper: newRESTMapper(externalVersions),
SelfLinker: runtime.SelfLinker(accessor),
InterfacesFor: interfacesFor,
}
if err := registered.RegisterGroup(groupMeta); err != nil {
return err
}
api.RegisterRESTMapper(groupMeta.RESTMapper)
return nil
}
func newRESTMapper(externalVersions []unversioned.GroupVersion) meta.RESTMapper {
// the list of kinds that are scoped at the root of the api hierarchy
// if a kind is not enumerated here, it is assumed to have a namespace scope
rootScoped := sets.NewString(
"Cluster",
)
ignoredKinds := sets.NewString()
return api.NewDefaultRESTMapper(externalVersions, interfacesFor, importPrefix, ignoredKinds, rootScoped)
}
// interfacesFor returns the default Codec and ResourceVersioner for a given version
// string, or an error if the version is not known.
func interfacesFor(version unversioned.GroupVersion) (*meta.VersionInterfaces, error) {
switch version {
case v1alpha1.SchemeGroupVersion:
return &meta.VersionInterfaces{
ObjectConvertor: api.Scheme,
MetadataAccessor: accessor,
}, nil
default:
g, _ := registered.Group(federation.GroupName)
return nil, fmt.Errorf("unsupported storage version: %s (valid: %v)", version, g.GroupVersions)
}
}
func addVersionsToScheme(externalVersions ...unversioned.GroupVersion) {
// add the internal version to Scheme
federation.AddToScheme(api.Scheme)
// add the enabled external versions to Scheme
for _, v := range externalVersions {
if !registered.IsEnabledVersion(v) {
glog.Errorf("Version %s is not enabled, so it will not be added to the Scheme.", v)
continue
}
switch v {
case v1alpha1.SchemeGroupVersion:
v1alpha1.AddToScheme(api.Scheme)
}
}
}

View File

@ -0,0 +1,118 @@
/*
Copyright 2016 The Kubernetes Authors 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 install
import (
"encoding/json"
"testing"
"k8s.io/kubernetes/federation/apis/federation"
"k8s.io/kubernetes/federation/apis/federation/v1alpha1"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apimachinery/registered"
"k8s.io/kubernetes/pkg/runtime"
)
func TestResourceVersioner(t *testing.T) {
cluster := federation.Cluster{ObjectMeta: api.ObjectMeta{ResourceVersion: "10"}}
version, err := accessor.ResourceVersion(&cluster)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if version != "10" {
t.Errorf("unexpected version %v", version)
}
clusterList := federation.ClusterList{ListMeta: unversioned.ListMeta{ResourceVersion: "10"}}
version, err = accessor.ResourceVersion(&clusterList)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if version != "10" {
t.Errorf("unexpected version %v", version)
}
}
func TestCodec(t *testing.T) {
cluster := federation.Cluster{}
// We do want to use package registered rather than testapi here, because we
// want to test if the package install and package registered work as expected.
data, err := runtime.Encode(api.Codecs.LegacyCodec(registered.GroupOrDie(federation.GroupName).GroupVersion), &cluster)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
other := federation.Cluster{}
if err := json.Unmarshal(data, &other); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if other.APIVersion != registered.GroupOrDie(federation.GroupName).GroupVersion.String() || other.Kind != "Cluster" {
t.Errorf("unexpected unmarshalled object %#v", other)
}
}
func TestInterfacesFor(t *testing.T) {
if _, err := registered.GroupOrDie(federation.GroupName).InterfacesFor(federation.SchemeGroupVersion); err == nil {
t.Fatalf("unexpected non-error: %v", err)
}
for i, version := range registered.GroupOrDie(federation.GroupName).GroupVersions {
if vi, err := registered.GroupOrDie(federation.GroupName).InterfacesFor(version); err != nil || vi == nil {
t.Fatalf("%d: unexpected result: %v", i, err)
}
}
}
func TestRESTMapper(t *testing.T) {
gv := v1alpha1.SchemeGroupVersion
clusterGVK := gv.WithKind("Cluster")
if gvk, err := registered.GroupOrDie(federation.GroupName).RESTMapper.KindFor(gv.WithResource("clusters")); err != nil || gvk != clusterGVK {
t.Errorf("unexpected version mapping: %v %v", gvk, err)
}
if m, err := registered.GroupOrDie(federation.GroupName).RESTMapper.RESTMapping(clusterGVK.GroupKind(), ""); err != nil || m.GroupVersionKind != clusterGVK || m.Resource != "clusters" {
t.Errorf("unexpected version mapping: %#v %v", m, err)
}
for _, version := range registered.GroupOrDie(federation.GroupName).GroupVersions {
mapping, err := registered.GroupOrDie(federation.GroupName).RESTMapper.RESTMapping(clusterGVK.GroupKind(), version.Version)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if mapping.Resource != "clusters" {
t.Errorf("incorrect resource name: %#v", mapping)
}
if mapping.GroupVersionKind.GroupVersion() != version {
t.Errorf("incorrect groupVersion: %v", mapping)
}
interfaces, _ := registered.GroupOrDie(federation.GroupName).InterfacesFor(version)
if mapping.ObjectConvertor != interfaces.ObjectConvertor {
t.Errorf("unexpected: %#v, expected: %#v", mapping, interfaces)
}
rc := &federation.Cluster{ObjectMeta: api.ObjectMeta{Name: "foo"}}
name, err := mapping.MetadataAccessor.Name(rc)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if name != "foo" {
t.Errorf("unable to retrieve object meta with: %v", mapping.MetadataAccessor)
}
}
}

View File

@ -0,0 +1,56 @@
/*
Copyright 2016 The Kubernetes Authors 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 federation
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/runtime"
)
// GroupName is the group name use in this package
const GroupName = "federation"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = unversioned.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
// Kind takes an unqualified kind and returns back a Group qualified GroupKind
func Kind(kind string) unversioned.GroupKind {
return SchemeGroupVersion.WithKind(kind).GroupKind()
}
// Resource takes an unqualified resource and returns back a Group qualified GroupResource
func Resource(resource string) unversioned.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
// Adds the list of known types to api.Scheme.
func AddToScheme(scheme *runtime.Scheme) {
addKnownTypes(scheme)
}
func addKnownTypes(scheme *runtime.Scheme) {
scheme.AddKnownTypes(SchemeGroupVersion,
&Cluster{},
&ClusterList{},
&api.ListOptions{},
&api.DeleteOptions{},
)
}
func (obj *Cluster) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
func (obj *ClusterList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,102 @@
/*
Copyright 2016 The Kubernetes Authors 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 federation
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
)
// ClusterSpec describes the attributes of a kubernetes cluster.
type ClusterSpec struct {
// A map of client CIDR to server address.
// This is to help clients reach servers in the most network-efficient way possible.
// Clients can use the appropriate server address as per the CIDR that they match.
// In case of multiple matches, clients should use the longest matching CIDR.
ServerAddressByClientCIDRs []unversioned.ServerAddressByClientCIDR `json:"serverAddressByClientCIDRs" patchStrategy:"merge" patchMergeKey:"clientCIDR"`
// the type (e.g. bearer token, client certificate etc) and data of the credential used to access cluster.
// Its used for system routines (not behalf of users)
// TODO: string may not enough, https://github.com/kubernetes/kubernetes/pull/23847#discussion_r59301275
Credential string `json:"credential,omitempty"`
}
type ClusterConditionType string
// These are valid conditions of a cluster.
const (
// ClusterReady means the cluster is ready to accept workloads.
ClusterReady ClusterConditionType = "Ready"
// ClusterOffline means the cluster is temporarily down or not reachable
ClusterOffline ClusterConditionType = "Offline"
)
// ClusterCondition describes current state of a cluster.
type ClusterCondition struct {
// Type of cluster condition, Complete or Failed.
Type ClusterConditionType `json:"type"`
// Status of the condition, one of True, False, Unknown.
Status api.ConditionStatus `json:"status"`
// Last time the condition was checked.
LastProbeTime unversioned.Time `json:"lastProbeTime,omitempty"`
// Last time the condition transit from one status to another.
LastTransitionTime unversioned.Time `json:"lastTransitionTime,omitempty"`
// (brief) reason for the condition's last transition.
Reason string `json:"reason,omitempty"`
// Human readable message indicating details about last transition.
Message string `json:"message,omitempty"`
}
// Cluster metadata
type ClusterMeta struct {
// Release version of the cluster.
Version string `json:"version,omitempty"`
}
// ClusterStatus is information about the current status of a cluster updated by cluster controller peridocally.
type ClusterStatus struct {
// Conditions is an array of current cluster conditions.
Conditions []ClusterCondition `json:"conditions,omitempty"`
// Capacity represents the total resources of the cluster
Capacity api.ResourceList `json:"capacity,omitempty"`
// Allocatable represents the total resources of a cluster that are available for scheduling.
Allocatable api.ResourceList `json:"allocatable,omitempty"`
ClusterMeta `json:",inline"`
}
// Information about a registered cluster in a federated kubernetes setup. Clusters are not namespaced and have unique names in the federation.
type Cluster struct {
unversioned.TypeMeta `json:",inline"`
// Standard object's metadata.
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata
api.ObjectMeta `json:"metadata,omitempty"`
// Spec defines the behavior of the Cluster.
Spec ClusterSpec `json:"spec,omitempty"`
// Status describes the current status of a Cluster
Status ClusterStatus `json:"status,omitempty"`
}
// A list of all the kubernetes clusters registered to the federation
type ClusterList struct {
unversioned.TypeMeta `json:",inline"`
// Standard list metadata.
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds
unversioned.ListMeta `json:"metadata,omitempty"`
// List of Cluster objects.
Items []Cluster `json:"items"`
}

View File

@ -0,0 +1,40 @@
/*
Copyright 2016 The Kubernetes Authors 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 v1alpha1
import (
"fmt"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/runtime"
)
func addConversionFuncs(scheme *runtime.Scheme) {
err := api.Scheme.AddFieldLabelConversionFunc(SchemeGroupVersion.String(), "Cluster",
func(label, value string) (string, string, error) {
switch label {
case "metadata.name":
return label, value, nil
default:
return "", "", fmt.Errorf("field label not supported: %s", label)
}
})
if err != nil {
// If one of the conversion functions is malformed, detect it immediately.
panic(err)
}
}

View File

@ -0,0 +1,351 @@
// +build !ignore_autogenerated
/*
Copyright 2016 The Kubernetes Authors 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.
*/
// This file was autogenerated by conversion-gen. Do not edit it manually!
package v1alpha1
import (
federation "k8s.io/kubernetes/federation/apis/federation"
api "k8s.io/kubernetes/pkg/api"
resource "k8s.io/kubernetes/pkg/api/resource"
unversioned "k8s.io/kubernetes/pkg/api/unversioned"
v1 "k8s.io/kubernetes/pkg/api/v1"
conversion "k8s.io/kubernetes/pkg/conversion"
reflect "reflect"
)
func init() {
if err := api.Scheme.AddGeneratedConversionFuncs(
Convert_v1alpha1_Cluster_To_federation_Cluster,
Convert_federation_Cluster_To_v1alpha1_Cluster,
Convert_v1alpha1_ClusterCondition_To_federation_ClusterCondition,
Convert_federation_ClusterCondition_To_v1alpha1_ClusterCondition,
Convert_v1alpha1_ClusterList_To_federation_ClusterList,
Convert_federation_ClusterList_To_v1alpha1_ClusterList,
Convert_v1alpha1_ClusterMeta_To_federation_ClusterMeta,
Convert_federation_ClusterMeta_To_v1alpha1_ClusterMeta,
Convert_v1alpha1_ClusterSpec_To_federation_ClusterSpec,
Convert_federation_ClusterSpec_To_v1alpha1_ClusterSpec,
Convert_v1alpha1_ClusterStatus_To_federation_ClusterStatus,
Convert_federation_ClusterStatus_To_v1alpha1_ClusterStatus,
); err != nil {
// if one of the conversion functions is malformed, detect it immediately.
panic(err)
}
}
func autoConvert_v1alpha1_Cluster_To_federation_Cluster(in *Cluster, out *federation.Cluster, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*Cluster))(in)
}
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
return err
}
// TODO: Inefficient conversion - can we improve it?
if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
return err
}
if err := Convert_v1alpha1_ClusterSpec_To_federation_ClusterSpec(&in.Spec, &out.Spec, s); err != nil {
return err
}
if err := Convert_v1alpha1_ClusterStatus_To_federation_ClusterStatus(&in.Status, &out.Status, s); err != nil {
return err
}
return nil
}
func Convert_v1alpha1_Cluster_To_federation_Cluster(in *Cluster, out *federation.Cluster, s conversion.Scope) error {
return autoConvert_v1alpha1_Cluster_To_federation_Cluster(in, out, s)
}
func autoConvert_federation_Cluster_To_v1alpha1_Cluster(in *federation.Cluster, out *Cluster, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*federation.Cluster))(in)
}
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
return err
}
// TODO: Inefficient conversion - can we improve it?
if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
return err
}
if err := Convert_federation_ClusterSpec_To_v1alpha1_ClusterSpec(&in.Spec, &out.Spec, s); err != nil {
return err
}
if err := Convert_federation_ClusterStatus_To_v1alpha1_ClusterStatus(&in.Status, &out.Status, s); err != nil {
return err
}
return nil
}
func Convert_federation_Cluster_To_v1alpha1_Cluster(in *federation.Cluster, out *Cluster, s conversion.Scope) error {
return autoConvert_federation_Cluster_To_v1alpha1_Cluster(in, out, s)
}
func autoConvert_v1alpha1_ClusterCondition_To_federation_ClusterCondition(in *ClusterCondition, out *federation.ClusterCondition, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*ClusterCondition))(in)
}
out.Type = federation.ClusterConditionType(in.Type)
out.Status = api.ConditionStatus(in.Status)
if err := api.Convert_unversioned_Time_To_unversioned_Time(&in.LastProbeTime, &out.LastProbeTime, s); err != nil {
return err
}
if err := api.Convert_unversioned_Time_To_unversioned_Time(&in.LastTransitionTime, &out.LastTransitionTime, s); err != nil {
return err
}
out.Reason = in.Reason
out.Message = in.Message
return nil
}
func Convert_v1alpha1_ClusterCondition_To_federation_ClusterCondition(in *ClusterCondition, out *federation.ClusterCondition, s conversion.Scope) error {
return autoConvert_v1alpha1_ClusterCondition_To_federation_ClusterCondition(in, out, s)
}
func autoConvert_federation_ClusterCondition_To_v1alpha1_ClusterCondition(in *federation.ClusterCondition, out *ClusterCondition, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*federation.ClusterCondition))(in)
}
out.Type = ClusterConditionType(in.Type)
out.Status = v1.ConditionStatus(in.Status)
if err := api.Convert_unversioned_Time_To_unversioned_Time(&in.LastProbeTime, &out.LastProbeTime, s); err != nil {
return err
}
if err := api.Convert_unversioned_Time_To_unversioned_Time(&in.LastTransitionTime, &out.LastTransitionTime, s); err != nil {
return err
}
out.Reason = in.Reason
out.Message = in.Message
return nil
}
func Convert_federation_ClusterCondition_To_v1alpha1_ClusterCondition(in *federation.ClusterCondition, out *ClusterCondition, s conversion.Scope) error {
return autoConvert_federation_ClusterCondition_To_v1alpha1_ClusterCondition(in, out, s)
}
func autoConvert_v1alpha1_ClusterList_To_federation_ClusterList(in *ClusterList, out *federation.ClusterList, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*ClusterList))(in)
}
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
return err
}
if err := api.Convert_unversioned_ListMeta_To_unversioned_ListMeta(&in.ListMeta, &out.ListMeta, s); err != nil {
return err
}
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]federation.Cluster, len(*in))
for i := range *in {
if err := Convert_v1alpha1_Cluster_To_federation_Cluster(&(*in)[i], &(*out)[i], s); err != nil {
return err
}
}
} else {
out.Items = nil
}
return nil
}
func Convert_v1alpha1_ClusterList_To_federation_ClusterList(in *ClusterList, out *federation.ClusterList, s conversion.Scope) error {
return autoConvert_v1alpha1_ClusterList_To_federation_ClusterList(in, out, s)
}
func autoConvert_federation_ClusterList_To_v1alpha1_ClusterList(in *federation.ClusterList, out *ClusterList, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*federation.ClusterList))(in)
}
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
return err
}
if err := api.Convert_unversioned_ListMeta_To_unversioned_ListMeta(&in.ListMeta, &out.ListMeta, s); err != nil {
return err
}
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]Cluster, len(*in))
for i := range *in {
if err := Convert_federation_Cluster_To_v1alpha1_Cluster(&(*in)[i], &(*out)[i], s); err != nil {
return err
}
}
} else {
out.Items = nil
}
return nil
}
func Convert_federation_ClusterList_To_v1alpha1_ClusterList(in *federation.ClusterList, out *ClusterList, s conversion.Scope) error {
return autoConvert_federation_ClusterList_To_v1alpha1_ClusterList(in, out, s)
}
func autoConvert_v1alpha1_ClusterMeta_To_federation_ClusterMeta(in *ClusterMeta, out *federation.ClusterMeta, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*ClusterMeta))(in)
}
out.Version = in.Version
return nil
}
func Convert_v1alpha1_ClusterMeta_To_federation_ClusterMeta(in *ClusterMeta, out *federation.ClusterMeta, s conversion.Scope) error {
return autoConvert_v1alpha1_ClusterMeta_To_federation_ClusterMeta(in, out, s)
}
func autoConvert_federation_ClusterMeta_To_v1alpha1_ClusterMeta(in *federation.ClusterMeta, out *ClusterMeta, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*federation.ClusterMeta))(in)
}
out.Version = in.Version
return nil
}
func Convert_federation_ClusterMeta_To_v1alpha1_ClusterMeta(in *federation.ClusterMeta, out *ClusterMeta, s conversion.Scope) error {
return autoConvert_federation_ClusterMeta_To_v1alpha1_ClusterMeta(in, out, s)
}
func autoConvert_v1alpha1_ClusterSpec_To_federation_ClusterSpec(in *ClusterSpec, out *federation.ClusterSpec, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*ClusterSpec))(in)
}
if in.ServerAddressByClientCIDRs != nil {
in, out := &in.ServerAddressByClientCIDRs, &out.ServerAddressByClientCIDRs
*out = make([]unversioned.ServerAddressByClientCIDR, len(*in))
for i := range *in {
// TODO: Inefficient conversion - can we improve it?
if err := s.Convert(&(*in)[i], &(*out)[i], 0); err != nil {
return err
}
}
} else {
out.ServerAddressByClientCIDRs = nil
}
out.Credential = in.Credential
return nil
}
func Convert_v1alpha1_ClusterSpec_To_federation_ClusterSpec(in *ClusterSpec, out *federation.ClusterSpec, s conversion.Scope) error {
return autoConvert_v1alpha1_ClusterSpec_To_federation_ClusterSpec(in, out, s)
}
func autoConvert_federation_ClusterSpec_To_v1alpha1_ClusterSpec(in *federation.ClusterSpec, out *ClusterSpec, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*federation.ClusterSpec))(in)
}
if in.ServerAddressByClientCIDRs != nil {
in, out := &in.ServerAddressByClientCIDRs, &out.ServerAddressByClientCIDRs
*out = make([]unversioned.ServerAddressByClientCIDR, len(*in))
for i := range *in {
// TODO: Inefficient conversion - can we improve it?
if err := s.Convert(&(*in)[i], &(*out)[i], 0); err != nil {
return err
}
}
} else {
out.ServerAddressByClientCIDRs = nil
}
out.Credential = in.Credential
return nil
}
func Convert_federation_ClusterSpec_To_v1alpha1_ClusterSpec(in *federation.ClusterSpec, out *ClusterSpec, s conversion.Scope) error {
return autoConvert_federation_ClusterSpec_To_v1alpha1_ClusterSpec(in, out, s)
}
func autoConvert_v1alpha1_ClusterStatus_To_federation_ClusterStatus(in *ClusterStatus, out *federation.ClusterStatus, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*ClusterStatus))(in)
}
if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions
*out = make([]federation.ClusterCondition, len(*in))
for i := range *in {
if err := Convert_v1alpha1_ClusterCondition_To_federation_ClusterCondition(&(*in)[i], &(*out)[i], s); err != nil {
return err
}
}
} else {
out.Conditions = nil
}
if err := v1.Convert_v1_ResourceList_To_api_ResourceList(&in.Capacity, &out.Capacity, s); err != nil {
return err
}
if err := v1.Convert_v1_ResourceList_To_api_ResourceList(&in.Allocatable, &out.Allocatable, s); err != nil {
return err
}
if err := Convert_v1alpha1_ClusterMeta_To_federation_ClusterMeta(&in.ClusterMeta, &out.ClusterMeta, s); err != nil {
return err
}
return nil
}
func Convert_v1alpha1_ClusterStatus_To_federation_ClusterStatus(in *ClusterStatus, out *federation.ClusterStatus, s conversion.Scope) error {
return autoConvert_v1alpha1_ClusterStatus_To_federation_ClusterStatus(in, out, s)
}
func autoConvert_federation_ClusterStatus_To_v1alpha1_ClusterStatus(in *federation.ClusterStatus, out *ClusterStatus, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*federation.ClusterStatus))(in)
}
if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions
*out = make([]ClusterCondition, len(*in))
for i := range *in {
if err := Convert_federation_ClusterCondition_To_v1alpha1_ClusterCondition(&(*in)[i], &(*out)[i], s); err != nil {
return err
}
}
} else {
out.Conditions = nil
}
if in.Capacity != nil {
in, out := &in.Capacity, &out.Capacity
*out = make(v1.ResourceList, len(*in))
for key, val := range *in {
newVal := new(resource.Quantity)
if err := api.Convert_resource_Quantity_To_resource_Quantity(&val, newVal, s); err != nil {
return err
}
(*out)[v1.ResourceName(key)] = *newVal
}
} else {
out.Capacity = nil
}
if in.Allocatable != nil {
in, out := &in.Allocatable, &out.Allocatable
*out = make(v1.ResourceList, len(*in))
for key, val := range *in {
newVal := new(resource.Quantity)
if err := api.Convert_resource_Quantity_To_resource_Quantity(&val, newVal, s); err != nil {
return err
}
(*out)[v1.ResourceName(key)] = *newVal
}
} else {
out.Allocatable = nil
}
if err := Convert_federation_ClusterMeta_To_v1alpha1_ClusterMeta(&in.ClusterMeta, &out.ClusterMeta, s); err != nil {
return err
}
return nil
}
func Convert_federation_ClusterStatus_To_v1alpha1_ClusterStatus(in *federation.ClusterStatus, out *ClusterStatus, s conversion.Scope) error {
return autoConvert_federation_ClusterStatus_To_v1alpha1_ClusterStatus(in, out, s)
}

View File

@ -0,0 +1,159 @@
// +build !ignore_autogenerated
/*
Copyright 2016 The Kubernetes Authors 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.
*/
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
package v1alpha1
import (
api "k8s.io/kubernetes/pkg/api"
resource "k8s.io/kubernetes/pkg/api/resource"
unversioned "k8s.io/kubernetes/pkg/api/unversioned"
v1 "k8s.io/kubernetes/pkg/api/v1"
conversion "k8s.io/kubernetes/pkg/conversion"
)
func init() {
if err := api.Scheme.AddGeneratedDeepCopyFuncs(
DeepCopy_v1alpha1_Cluster,
DeepCopy_v1alpha1_ClusterCondition,
DeepCopy_v1alpha1_ClusterList,
DeepCopy_v1alpha1_ClusterMeta,
DeepCopy_v1alpha1_ClusterSpec,
DeepCopy_v1alpha1_ClusterStatus,
); err != nil {
// if one of the deep copy functions is malformed, detect it immediately.
panic(err)
}
}
func DeepCopy_v1alpha1_Cluster(in Cluster, out *Cluster, c *conversion.Cloner) error {
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
return err
}
if err := v1.DeepCopy_v1_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil {
return err
}
if err := DeepCopy_v1alpha1_ClusterSpec(in.Spec, &out.Spec, c); err != nil {
return err
}
if err := DeepCopy_v1alpha1_ClusterStatus(in.Status, &out.Status, c); err != nil {
return err
}
return nil
}
func DeepCopy_v1alpha1_ClusterCondition(in ClusterCondition, out *ClusterCondition, c *conversion.Cloner) error {
out.Type = in.Type
out.Status = in.Status
if err := unversioned.DeepCopy_unversioned_Time(in.LastProbeTime, &out.LastProbeTime, c); err != nil {
return err
}
if err := unversioned.DeepCopy_unversioned_Time(in.LastTransitionTime, &out.LastTransitionTime, c); err != nil {
return err
}
out.Reason = in.Reason
out.Message = in.Message
return nil
}
func DeepCopy_v1alpha1_ClusterList(in ClusterList, out *ClusterList, c *conversion.Cloner) error {
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
return err
}
if err := unversioned.DeepCopy_unversioned_ListMeta(in.ListMeta, &out.ListMeta, c); err != nil {
return err
}
if in.Items != nil {
in, out := in.Items, &out.Items
*out = make([]Cluster, len(in))
for i := range in {
if err := DeepCopy_v1alpha1_Cluster(in[i], &(*out)[i], c); err != nil {
return err
}
}
} else {
out.Items = nil
}
return nil
}
func DeepCopy_v1alpha1_ClusterMeta(in ClusterMeta, out *ClusterMeta, c *conversion.Cloner) error {
out.Version = in.Version
return nil
}
func DeepCopy_v1alpha1_ClusterSpec(in ClusterSpec, out *ClusterSpec, c *conversion.Cloner) error {
if in.ServerAddressByClientCIDRs != nil {
in, out := in.ServerAddressByClientCIDRs, &out.ServerAddressByClientCIDRs
*out = make([]unversioned.ServerAddressByClientCIDR, len(in))
for i := range in {
if err := unversioned.DeepCopy_unversioned_ServerAddressByClientCIDR(in[i], &(*out)[i], c); err != nil {
return err
}
}
} else {
out.ServerAddressByClientCIDRs = nil
}
out.Credential = in.Credential
return nil
}
func DeepCopy_v1alpha1_ClusterStatus(in ClusterStatus, out *ClusterStatus, c *conversion.Cloner) error {
if in.Conditions != nil {
in, out := in.Conditions, &out.Conditions
*out = make([]ClusterCondition, len(in))
for i := range in {
if err := DeepCopy_v1alpha1_ClusterCondition(in[i], &(*out)[i], c); err != nil {
return err
}
}
} else {
out.Conditions = nil
}
if in.Capacity != nil {
in, out := in.Capacity, &out.Capacity
*out = make(v1.ResourceList)
for key, val := range in {
newVal := new(resource.Quantity)
if err := resource.DeepCopy_resource_Quantity(val, newVal, c); err != nil {
return err
}
(*out)[key] = *newVal
}
} else {
out.Capacity = nil
}
if in.Allocatable != nil {
in, out := in.Allocatable, &out.Allocatable
*out = make(v1.ResourceList)
for key, val := range in {
newVal := new(resource.Quantity)
if err := resource.DeepCopy_resource_Quantity(val, newVal, c); err != nil {
return err
}
(*out)[key] = *newVal
}
} else {
out.Allocatable = nil
}
if err := DeepCopy_v1alpha1_ClusterMeta(in.ClusterMeta, &out.ClusterMeta, c); err != nil {
return err
}
return nil
}

View File

@ -0,0 +1,24 @@
/*
Copyright 2016 The Kubernetes Authors 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 v1alpha1
import (
"k8s.io/kubernetes/pkg/runtime"
)
func addDefaultingFuncs(scheme *runtime.Scheme) {
}

View File

@ -0,0 +1,18 @@
/*
Copyright 2016 The Kubernetes Authors 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.
*/
// +genconversion=true
package v1alpha1

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,109 @@
/*
Copyright 2016 The Kubernetes Authors 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.
*/
// This file was autogenerated by go-to-protobuf. Do not edit it manually!
syntax = 'proto2';
package k8s.io.kubernetes.federation.apis.federation.v1alpha1;
import "k8s.io/kubernetes/pkg/api/resource/generated.proto";
import "k8s.io/kubernetes/pkg/api/unversioned/generated.proto";
import "k8s.io/kubernetes/pkg/api/v1/generated.proto";
import "k8s.io/kubernetes/pkg/util/intstr/generated.proto";
// Package-wide variables from generator "generated".
option go_package = "v1alpha1";
// Information about a registered cluster in a federated kubernetes setup. Clusters are not namespaced and have unique names in the federation.
message Cluster {
// Standard object's metadata.
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata
optional k8s.io.kubernetes.pkg.api.v1.ObjectMeta metadata = 1;
// Spec defines the behavior of the Cluster.
optional ClusterSpec spec = 2;
// Status describes the current status of a Cluster
optional ClusterStatus status = 3;
}
// ClusterCondition describes current state of a cluster.
message ClusterCondition {
// Type of cluster condition, Complete or Failed.
optional string type = 1;
// Status of the condition, one of True, False, Unknown.
optional string status = 2;
// Last time the condition was checked.
optional k8s.io.kubernetes.pkg.api.unversioned.Time lastProbeTime = 3;
// Last time the condition transit from one status to another.
optional k8s.io.kubernetes.pkg.api.unversioned.Time lastTransitionTime = 4;
// (brief) reason for the condition's last transition.
optional string reason = 5;
// Human readable message indicating details about last transition.
optional string message = 6;
}
// A list of all the kubernetes clusters registered to the federation
message ClusterList {
// Standard list metadata.
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds
optional k8s.io.kubernetes.pkg.api.unversioned.ListMeta metadata = 1;
// List of Cluster objects.
repeated Cluster items = 2;
}
// Cluster metadata
message ClusterMeta {
// Release version of the cluster.
optional string version = 1;
}
// ClusterSpec describes the attributes of a kubernetes cluster.
message ClusterSpec {
// A map of client CIDR to server address.
// This is to help clients reach servers in the most network-efficient way possible.
// Clients can use the appropriate server address as per the CIDR that they match.
// In case of multiple matches, clients should use the longest matching CIDR.
repeated k8s.io.kubernetes.pkg.api.unversioned.ServerAddressByClientCIDR serverAddressByClientCIDRs = 1;
// the type (e.g. bearer token, client certificate etc) and data of the credential used to access cluster.
// Its used for system routines (not behalf of users)
// TODO: string may not enough, https://github.com/kubernetes/kubernetes/pull/23847#discussion_r59301275
optional string credential = 2;
}
// ClusterStatus is information about the current status of a cluster updated by cluster controller peridocally.
message ClusterStatus {
// Conditions is an array of current cluster conditions.
repeated ClusterCondition conditions = 1;
// Capacity represents the total resources of the cluster
map<string, k8s.io.kubernetes.pkg.api.resource.Quantity> capacity = 2;
// Allocatable represents the total resources of a cluster that are available for scheduling.
map<string, k8s.io.kubernetes.pkg.api.resource.Quantity> allocatable = 3;
optional ClusterMeta clusterMeta = 4;
}

View File

@ -0,0 +1,50 @@
/*
Copyright 2016 The Kubernetes Authors 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 v1alpha1
import (
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/runtime"
versionedwatch "k8s.io/kubernetes/pkg/watch/versioned"
)
// GroupName is the group name use in this package
const GroupName = "federation"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = unversioned.GroupVersion{Group: GroupName, Version: "v1alpha1"}
// Adds the list of known types to api.Scheme.
func AddToScheme(scheme *runtime.Scheme) {
addKnownTypes(scheme)
addDefaultingFuncs(scheme)
addConversionFuncs(scheme)
}
func addKnownTypes(scheme *runtime.Scheme) {
scheme.AddKnownTypes(SchemeGroupVersion,
&Cluster{},
&ClusterList{},
&v1.ListOptions{},
&v1.DeleteOptions{},
)
versionedwatch.AddToGroupVersion(scheme, SchemeGroupVersion)
}
func (obj *Cluster) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
func (obj *ClusterList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,102 @@
/*
Copyright 2016 The Kubernetes Authors 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 v1alpha1
import (
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/v1"
)
// ClusterSpec describes the attributes of a kubernetes cluster.
type ClusterSpec struct {
// A map of client CIDR to server address.
// This is to help clients reach servers in the most network-efficient way possible.
// Clients can use the appropriate server address as per the CIDR that they match.
// In case of multiple matches, clients should use the longest matching CIDR.
ServerAddressByClientCIDRs []unversioned.ServerAddressByClientCIDR `json:"serverAddressByClientCIDRs" patchStrategy:"merge" patchMergeKey:"clientCIDR" protobuf:"bytes,1,rep,name=serverAddressByClientCIDRs"`
// the type (e.g. bearer token, client certificate etc) and data of the credential used to access cluster.
// Its used for system routines (not behalf of users)
// TODO: string may not enough, https://github.com/kubernetes/kubernetes/pull/23847#discussion_r59301275
Credential string `json:"credential,omitempty" protobuf:"bytes,2,opt,name=credential"`
}
type ClusterConditionType string
// These are valid conditions of a cluster.
const (
// ClusterReady means the cluster is ready to accept workloads.
ClusterReady ClusterConditionType = "Ready"
// ClusterOffline means the cluster is temporarily down or not reachable
ClusterOffline ClusterConditionType = "Offline"
)
// ClusterCondition describes current state of a cluster.
type ClusterCondition struct {
// Type of cluster condition, Complete or Failed.
Type ClusterConditionType `json:"type" protobuf:"bytes,1,opt,name=type,casttype=ClusterConditionType"`
// Status of the condition, one of True, False, Unknown.
Status v1.ConditionStatus `json:"status" protobuf:"bytes,2,opt,name=status,casttype=k8s.io/kubernetes/pkg/api/v1.ConditionStatus"`
// Last time the condition was checked.
LastProbeTime unversioned.Time `json:"lastProbeTime,omitempty" protobuf:"bytes,3,opt,name=lastProbeTime"`
// Last time the condition transit from one status to another.
LastTransitionTime unversioned.Time `json:"lastTransitionTime,omitempty" protobuf:"bytes,4,opt,name=lastTransitionTime"`
// (brief) reason for the condition's last transition.
Reason string `json:"reason,omitempty" protobuf:"bytes,5,opt,name=reason"`
// Human readable message indicating details about last transition.
Message string `json:"message,omitempty" protobuf:"bytes,6,opt,name=message"`
}
// Cluster metadata
type ClusterMeta struct {
// Release version of the cluster.
Version string `json:"version,omitempty" protobuf:"bytes,1,opt,name=version"`
}
// ClusterStatus is information about the current status of a cluster updated by cluster controller peridocally.
type ClusterStatus struct {
// Conditions is an array of current cluster conditions.
Conditions []ClusterCondition `json:"conditions,omitempty" protobuf:"bytes,1,rep,name=conditions"`
// Capacity represents the total resources of the cluster
Capacity v1.ResourceList `json:"capacity,omitempty" protobuf:"bytes,2,rep,name=capacity,casttype=k8s.io/kubernetes/pkg/api/v1.ResourceList,castkey=k8s.io/kubernetes/pkg/api/v1.ResourceName"`
// Allocatable represents the total resources of a cluster that are available for scheduling.
Allocatable v1.ResourceList `json:"allocatable,omitempty" protobuf:"bytes,3,rep,name=allocatable,casttype=k8s.io/kubernetes/pkg/api/v1.ResourceList,castkey=k8s.io/kubernetes/pkg/api/v1.ResourceName"`
ClusterMeta `json:",inline" protobuf:"bytes,4,opt,name=clusterMeta"`
}
// Information about a registered cluster in a federated kubernetes setup. Clusters are not namespaced and have unique names in the federation.
type Cluster struct {
unversioned.TypeMeta `json:",inline"`
// Standard object's metadata.
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata
v1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
// Spec defines the behavior of the Cluster.
Spec ClusterSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
// Status describes the current status of a Cluster
Status ClusterStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}
// A list of all the kubernetes clusters registered to the federation
type ClusterList struct {
unversioned.TypeMeta `json:",inline"`
// Standard list metadata.
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds
unversioned.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
// List of Cluster objects.
Items []Cluster `json:"items" protobuf:"bytes,2,rep,name=items"`
}

View File

@ -0,0 +1,56 @@
/*
Copyright 2016 The Kubernetes Authors 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 (
"k8s.io/kubernetes/federation/apis/federation"
"k8s.io/kubernetes/pkg/api/validation"
"k8s.io/kubernetes/pkg/util/validation/field"
)
func ValidateClusterName(name string, prefix bool) (bool, string) {
return validation.NameIsDNSSubdomain(name, prefix)
}
func ValidateClusterSpec(spec *federation.ClusterSpec, fieldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
// address is required.
if len(spec.ServerAddressByClientCIDRs) == 0 {
allErrs = append(allErrs, field.Required(fieldPath.Child("serverAddressByClientCIDRs"), ""))
}
return allErrs
}
func ValidateCluster(cluster *federation.Cluster) field.ErrorList {
allErrs := validation.ValidateObjectMeta(&cluster.ObjectMeta, false, ValidateClusterName, field.NewPath("metadata"))
allErrs = append(allErrs, ValidateClusterSpec(&cluster.Spec, field.NewPath("spec"))...)
return allErrs
}
func ValidateClusterUpdate(cluster, oldCluster *federation.Cluster) field.ErrorList {
allErrs := validation.ValidateObjectMetaUpdate(&cluster.ObjectMeta, &oldCluster.ObjectMeta, field.NewPath("metadata"))
if cluster.Name != oldCluster.Name {
allErrs = append(allErrs, field.Invalid(field.NewPath("meta", "name"),
cluster.Name+" != "+oldCluster.Name, "cannot change cluster name"))
}
return allErrs
}
func ValidateClusterStatusUpdate(cluster, oldCluster *federation.Cluster) field.ErrorList {
allErrs := validation.ValidateObjectMetaUpdate(&cluster.ObjectMeta, &oldCluster.ObjectMeta, field.NewPath("metadata"))
return allErrs
}

View File

@ -0,0 +1,206 @@
/*
Copyright 2016 The Kubernetes Authors 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 (
"testing"
"k8s.io/kubernetes/federation/apis/federation"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
)
func TestValidateCluster(t *testing.T) {
successCases := []federation.Cluster{
{
ObjectMeta: api.ObjectMeta{Name: "cluster-s"},
Spec: federation.ClusterSpec{
ServerAddressByClientCIDRs: []unversioned.ServerAddressByClientCIDR{
{
ClientCIDR: "0.0.0.0/0",
ServerAddress: "localhost:8888",
},
},
},
},
}
for _, successCase := range successCases {
errs := ValidateCluster(&successCase)
if len(errs) != 0 {
t.Errorf("expect success: %v", errs)
}
}
errorCases := map[string]federation.Cluster{
"missing cluster addresses": {
ObjectMeta: api.ObjectMeta{Name: "cluster-f"},
},
"empty cluster addresses": {
ObjectMeta: api.ObjectMeta{Name: "cluster-f"},
Spec: federation.ClusterSpec{
ServerAddressByClientCIDRs: []unversioned.ServerAddressByClientCIDR{},
}},
"invalid_label": {
ObjectMeta: api.ObjectMeta{
Name: "cluster-f",
Labels: map[string]string{
"NoUppercaseOrSpecialCharsLike=Equals": "bar",
},
},
},
}
for testName, errorCase := range errorCases {
errs := ValidateCluster(&errorCase)
if len(errs) == 0 {
t.Errorf("expected failur for %s", testName)
}
}
}
func TestValidateClusterUpdate(t *testing.T) {
type clusterUpdateTest struct {
old federation.Cluster
update federation.Cluster
}
successCases := []clusterUpdateTest{
{
old: federation.Cluster{
ObjectMeta: api.ObjectMeta{Name: "cluster-s"},
Spec: federation.ClusterSpec{
ServerAddressByClientCIDRs: []unversioned.ServerAddressByClientCIDR{
{
ClientCIDR: "0.0.0.0/0",
ServerAddress: "localhost:8888",
},
},
},
},
update: federation.Cluster{
ObjectMeta: api.ObjectMeta{Name: "cluster-s"},
Spec: federation.ClusterSpec{
ServerAddressByClientCIDRs: []unversioned.ServerAddressByClientCIDR{
{
ClientCIDR: "0.0.0.0/0",
ServerAddress: "localhost:8888",
},
},
},
},
},
}
for _, successCase := range successCases {
successCase.old.ObjectMeta.ResourceVersion = "1"
successCase.update.ObjectMeta.ResourceVersion = "1"
errs := ValidateClusterUpdate(&successCase.update, &successCase.old)
if len(errs) != 0 {
t.Errorf("expect success: %v", errs)
}
}
errorCases := map[string]clusterUpdateTest{
"cluster name changed": {
old: federation.Cluster{
ObjectMeta: api.ObjectMeta{Name: "cluster-s"},
Spec: federation.ClusterSpec{
ServerAddressByClientCIDRs: []unversioned.ServerAddressByClientCIDR{
{
ClientCIDR: "0.0.0.0/0",
ServerAddress: "localhost:8888",
},
},
},
},
update: federation.Cluster{
ObjectMeta: api.ObjectMeta{Name: "cluster-newname"},
Spec: federation.ClusterSpec{
ServerAddressByClientCIDRs: []unversioned.ServerAddressByClientCIDR{
{
ClientCIDR: "0.0.0.0/0",
ServerAddress: "localhost:8888",
},
},
},
},
},
}
for testName, errorCase := range errorCases {
errs := ValidateClusterUpdate(&errorCase.update, &errorCase.old)
if len(errs) == 0 {
t.Errorf("expected failure: %s", testName)
}
}
}
func TestValidateClusterStatusUpdate(t *testing.T) {
type clusterUpdateTest struct {
old federation.Cluster
update federation.Cluster
}
successCases := []clusterUpdateTest{
{
old: federation.Cluster{
ObjectMeta: api.ObjectMeta{Name: "cluster-s"},
Spec: federation.ClusterSpec{
ServerAddressByClientCIDRs: []unversioned.ServerAddressByClientCIDR{
{
ClientCIDR: "0.0.0.0/0",
ServerAddress: "localhost:8888",
},
},
},
Status: federation.ClusterStatus{
Conditions: []federation.ClusterCondition{
{Type: federation.ClusterReady, Status: api.ConditionTrue},
},
},
},
update: federation.Cluster{
ObjectMeta: api.ObjectMeta{Name: "cluster-s"},
Spec: federation.ClusterSpec{
ServerAddressByClientCIDRs: []unversioned.ServerAddressByClientCIDR{
{
ClientCIDR: "0.0.0.0/0",
ServerAddress: "localhost:8888",
},
},
},
Status: federation.ClusterStatus{
Conditions: []federation.ClusterCondition{
{Type: federation.ClusterReady, Status: api.ConditionTrue},
{Type: federation.ClusterOffline, Status: api.ConditionTrue},
},
},
},
},
}
for _, successCase := range successCases {
successCase.old.ObjectMeta.ResourceVersion = "1"
successCase.update.ObjectMeta.ResourceVersion = "1"
errs := ValidateClusterUpdate(&successCase.update, &successCase.old)
if len(errs) != 0 {
t.Errorf("expect success: %v", errs)
}
}
errorCases := map[string]clusterUpdateTest{}
for testName, errorCase := range errorCases {
errs := ValidateClusterStatusUpdate(&errorCase.update, &errorCase.old)
if len(errs) == 0 {
t.Errorf("expected failure: %s", testName)
}
}
}

View File

@ -0,0 +1,62 @@
/*
Copyright 2016 The Kubernetes Authors 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 app
import (
"github.com/golang/glog"
"k8s.io/kubernetes/federation/apis/federation"
"k8s.io/kubernetes/federation/cmd/federated-apiserver/app/options"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/apimachinery/registered"
"k8s.io/kubernetes/pkg/genericapiserver"
"k8s.io/kubernetes/pkg/registry/generic"
_ "k8s.io/kubernetes/federation/apis/federation/install"
clusteretcd "k8s.io/kubernetes/federation/registry/cluster/etcd"
)
func installFederationAPIs(s *options.APIServer, g *genericapiserver.GenericAPIServer, f genericapiserver.StorageFactory) {
storage, err := f.New(federation.Resource("clusters"))
if err != nil {
glog.Fatalf("Unable to find storage destination for %v, due to %v", "clusters", err.Error())
}
clusterStorage, clusterStatusStorage := clusteretcd.NewREST(generic.RESTOptions{
Storage: storage,
Decorator: g.StorageDecorator(),
DeleteCollectionWorkers: s.DeleteCollectionWorkers,
})
federationResources := map[string]rest.Storage{
"clusters": clusterStorage,
"clusters/status": clusterStatusStorage,
}
federationGroupMeta := registered.GroupOrDie(federation.GroupName)
apiGroupInfo := genericapiserver.APIGroupInfo{
GroupMeta: *federationGroupMeta,
VersionedResourcesStorageMap: map[string]map[string]rest.Storage{
"v1alpha1": federationResources,
},
OptionsExternalVersion: &registered.GroupOrDie(api.GroupName).GroupVersion,
Scheme: api.Scheme,
ParameterCodec: api.ParameterCodec,
NegotiatedSerializer: api.Codecs,
}
if err := g.InstallAPIGroup(&apiGroupInfo); err != nil {
glog.Fatalf("Error in registering group versions: %v", err)
}
}

View File

@ -295,6 +295,8 @@ func Run(s *options.APIServer) error {
return err
}
installFederationAPIs(s, m, storageFactory)
m.Run(s.ServerRunOptions)
return nil
}

View File

@ -20,7 +20,16 @@ import (
"regexp"
"testing"
"encoding/json"
"fmt"
"github.com/stretchr/testify/assert"
"io/ioutil"
fed_v1a1 "k8s.io/kubernetes/federation/apis/federation/v1alpha1"
"k8s.io/kubernetes/federation/cmd/federated-apiserver/app/options"
"k8s.io/kubernetes/pkg/api/unversioned"
"net"
"net/http"
"time"
)
func TestLongRunningRequestRegexp(t *testing.T) {
@ -63,3 +72,145 @@ func TestLongRunningRequestRegexp(t *testing.T) {
}
}
}
var insecurePort = 8081
var serverIP = fmt.Sprintf("http://localhost:%v", insecurePort)
var groupVersion = fed_v1a1.SchemeGroupVersion
func TestRun(t *testing.T) {
s := options.NewAPIServer()
s.InsecurePort = insecurePort
_, ipNet, _ := net.ParseCIDR("10.10.10.0/24")
s.ServiceClusterIPRange = *ipNet
s.EtcdConfig.ServerList = []string{"http://localhost:4001"}
go func() {
if err := Run(s); err != nil {
t.Fatalf("Error in bringing up the server: %v", err)
}
}()
if err := waitForApiserverUp(); err != nil {
t.Fatalf("%v", err)
}
testSwaggerSpec(t)
testAPIGroupList(t)
testAPIGroup(t)
testAPIResourceList(t)
}
func waitForApiserverUp() error {
for start := time.Now(); time.Since(start) < time.Minute; time.Sleep(5 * time.Second) {
_, err := http.Get(serverIP)
if err == nil {
return nil
}
}
return fmt.Errorf("waiting for apiserver timed out")
}
func readResponse(serverURL string) ([]byte, error) {
response, err := http.Get(serverURL)
if err != nil {
return nil, fmt.Errorf("Error in fetching %s: %v", serverURL, err)
}
defer response.Body.Close()
if response.StatusCode != http.StatusOK {
return nil, fmt.Errorf("unexpected status: %d for URL: %s, expected status: %d", response.StatusCode, serverURL, http.StatusOK)
}
contents, err := ioutil.ReadAll(response.Body)
if err != nil {
return nil, fmt.Errorf("Error reading response from %s: %v", serverURL, err)
}
return contents, nil
}
func testSwaggerSpec(t *testing.T) {
serverURL := serverIP + "/swaggerapi"
_, err := readResponse(serverURL)
if err != nil {
t.Fatalf("%v", err)
}
}
func findGroup(groups []unversioned.APIGroup, groupName string) *unversioned.APIGroup {
for _, group := range groups {
if group.Name == groupName {
return &group
}
}
return nil
}
func testAPIGroupList(t *testing.T) {
var groupVersionForDiscovery = unversioned.GroupVersionForDiscovery{
GroupVersion: groupVersion.String(),
Version: groupVersion.Version,
}
serverURL := serverIP + "/apis"
contents, err := readResponse(serverURL)
if err != nil {
t.Fatalf("%v", err)
}
var apiGroupList unversioned.APIGroupList
err = json.Unmarshal(contents, &apiGroupList)
if err != nil {
t.Fatalf("Error in unmarshalling response from server %s: %v", serverURL, err)
}
found := findGroup(apiGroupList.Groups, groupVersion.Group)
assert.NotNil(t, found)
assert.Equal(t, found.Name, groupVersion.Group)
assert.Equal(t, 1, len(found.Versions))
assert.Equal(t, found.Versions[0], groupVersionForDiscovery)
assert.Equal(t, found.PreferredVersion, groupVersionForDiscovery)
}
func testAPIGroup(t *testing.T) {
serverURL := serverIP + "/apis/federation"
contents, err := readResponse(serverURL)
if err != nil {
t.Fatalf("%v", err)
}
var apiGroup unversioned.APIGroup
err = json.Unmarshal(contents, &apiGroup)
if err != nil {
t.Fatalf("Error in unmarshalling response from server %s: %v", serverURL, err)
}
assert.Equal(t, apiGroup.APIVersion, "v1")
assert.Equal(t, apiGroup.Name, groupVersion.Group)
assert.Equal(t, 1, len(apiGroup.Versions))
assert.Equal(t, apiGroup.Versions[0].GroupVersion, groupVersion.String())
assert.Equal(t, apiGroup.Versions[0].Version, groupVersion.Version)
assert.Equal(t, apiGroup.Versions[0], apiGroup.PreferredVersion)
}
func findResource(resources []unversioned.APIResource, resourceName string) *unversioned.APIResource {
for _, resource := range resources {
if resource.Name == resourceName {
return &resource
}
}
return nil
}
func testAPIResourceList(t *testing.T) {
serverURL := serverIP + "/apis/federation/v1alpha1"
contents, err := readResponse(serverURL)
if err != nil {
t.Fatalf("%v", err)
}
var apiResourceList unversioned.APIResourceList
err = json.Unmarshal(contents, &apiResourceList)
if err != nil {
t.Fatalf("Error in unmarshalling response from server %s: %v", serverURL, err)
}
assert.Equal(t, apiResourceList.APIVersion, "v1")
assert.Equal(t, apiResourceList.GroupVersion, groupVersion.String())
found := findResource(apiResourceList.APIResources, "clusters")
assert.NotNil(t, found)
assert.False(t, found.Namespaced)
found = findResource(apiResourceList.APIResources, "clusters/status")
assert.NotNil(t, found)
assert.False(t, found.Namespaced)
}

View File

@ -0,0 +1,82 @@
/*
Copyright 2016 The Kubernetes Authors 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 etcd
import (
"k8s.io/kubernetes/federation/apis/federation"
"k8s.io/kubernetes/federation/registry/cluster"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/registry/generic/registry"
"k8s.io/kubernetes/pkg/runtime"
)
type REST struct {
*registry.Store
}
type StatusREST struct {
store *registry.Store
}
func (r *StatusREST) New() runtime.Object {
return &federation.Cluster{}
}
// Update alters the status subset of an object.
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
return r.store.Update(ctx, obj)
}
// NewREST returns a RESTStorage object that will work against clusters.
func NewREST(opts generic.RESTOptions) (*REST, *StatusREST) {
prefix := "/clusters"
newListFunc := func() runtime.Object { return &federation.ClusterList{} }
storageInterface := opts.Decorator(
opts.Storage, 100, &federation.Cluster{}, prefix, cluster.Strategy, newListFunc)
store := &registry.Store{
NewFunc: func() runtime.Object { return &federation.Cluster{} },
NewListFunc: newListFunc,
KeyRootFunc: func(ctx api.Context) string {
return prefix
},
KeyFunc: func(ctx api.Context, name string) (string, error) {
return registry.NoNamespaceKeyFunc(ctx, prefix, name)
},
ObjectNameFunc: func(obj runtime.Object) (string, error) {
return obj.(*federation.Cluster).Name, nil
},
PredicateFunc: cluster.MatchCluster,
QualifiedResource: federation.Resource("clusters"),
DeleteCollectionWorkers: opts.DeleteCollectionWorkers,
CreateStrategy: cluster.Strategy,
UpdateStrategy: cluster.Strategy,
DeleteStrategy: cluster.Strategy,
ReturnDeletedObject: true,
Storage: storageInterface,
}
statusStore := *store
statusStore.UpdateStrategy = cluster.StatusStrategy
return &REST{store}, &StatusREST{store: &statusStore}
}

View File

@ -0,0 +1,142 @@
/*
Copyright 2016 The Kubernetes Authors 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 etcd
import (
"testing"
"k8s.io/kubernetes/federation/apis/federation"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/registry/registrytest"
"k8s.io/kubernetes/pkg/runtime"
etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing"
)
func newStorage(t *testing.T) (*REST, *etcdtesting.EtcdTestServer) {
etcdStorage, server := registrytest.NewEtcdStorage(t, federation.GroupName)
restOptions := generic.RESTOptions{
Storage: etcdStorage,
Decorator: generic.UndecoratedStorage,
DeleteCollectionWorkers: 1}
storage, _ := NewREST(restOptions)
return storage, server
}
func validNewCluster() *federation.Cluster {
return &federation.Cluster{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Labels: map[string]string{
"name": "foo",
},
},
Spec: federation.ClusterSpec{
ServerAddressByClientCIDRs: []unversioned.ServerAddressByClientCIDR{
{
ClientCIDR: "0.0.0.0/0",
ServerAddress: "localhost:8888",
},
},
},
Status: federation.ClusterStatus{
Conditions: []federation.ClusterCondition{
{Type: federation.ClusterReady, Status: api.ConditionFalse},
},
},
}
}
func TestCreate(t *testing.T) {
storage, server := newStorage(t)
defer server.Terminate(t)
test := registrytest.New(t, storage.Store).ClusterScope()
cluster := validNewCluster()
cluster.ObjectMeta = api.ObjectMeta{GenerateName: "foo"}
test.TestCreate(
cluster,
&federation.Cluster{
ObjectMeta: api.ObjectMeta{Name: "-a123-a_"},
},
)
}
func TestUpdate(t *testing.T) {
storage, server := newStorage(t)
defer server.Terminate(t)
test := registrytest.New(t, storage.Store).ClusterScope()
test.TestUpdate(
// valid
validNewCluster(),
// updateFunc
func(obj runtime.Object) runtime.Object {
object := obj.(*federation.Cluster)
object.Spec.Credential = "bar"
return object
},
)
}
func TestDelete(t *testing.T) {
storage, server := newStorage(t)
defer server.Terminate(t)
test := registrytest.New(t, storage.Store).ClusterScope().ReturnDeletedObject()
test.TestDelete(validNewCluster())
}
func TestGet(t *testing.T) {
storage, server := newStorage(t)
defer server.Terminate(t)
test := registrytest.New(t, storage.Store).ClusterScope()
test.TestGet(validNewCluster())
}
func TestList(t *testing.T) {
storage, server := newStorage(t)
defer server.Terminate(t)
test := registrytest.New(t, storage.Store).ClusterScope()
test.TestList(validNewCluster())
}
func TestWatch(t *testing.T) {
storage, server := newStorage(t)
defer server.Terminate(t)
test := registrytest.New(t, storage.Store).ClusterScope()
test.TestWatch(
validNewCluster(),
// matching labels
[]labels.Set{
{"name": "foo"},
},
// not matching labels
[]labels.Set{
{"name": "bar"},
{"foo": "bar"},
},
// matching fields
[]fields.Set{
{"metadata.name": "foo"},
},
// not matching fields
[]fields.Set{
{"metadata.name": "bar"},
},
)
}

View File

@ -0,0 +1,81 @@
/*
Copyright 2016 The Kubernetes Authors 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 cluster
import (
"k8s.io/kubernetes/federation/apis/federation"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/watch"
)
// Registry is an interface implemented by things that know how to store Cluster objects.
type Registry interface {
ListClusters(ctx api.Context, options *api.ListOptions) (*federation.ClusterList, error)
WatchCluster(ctx api.Context, options *api.ListOptions) (watch.Interface, error)
GetCluster(ctx api.Context, name string) (*federation.Cluster, error)
CreateCluster(ctx api.Context, cluster *federation.Cluster) error
UpdateCluster(ctx api.Context, cluster *federation.Cluster) error
DeleteCluster(ctx api.Context, name string) error
}
// storage puts strong typing around storage calls
type storage struct {
rest.StandardStorage
}
// NewRegistry returns a new Registry interface for the given Storage. Any mismatched
// types will panic.
func NewRegistry(s rest.StandardStorage) Registry {
return &storage{s}
}
func (s *storage) ListClusters(ctx api.Context, options *api.ListOptions) (*federation.ClusterList, error) {
obj, err := s.List(ctx, options)
if err != nil {
return nil, err
}
return obj.(*federation.ClusterList), nil
}
func (s *storage) WatchCluster(ctx api.Context, options *api.ListOptions) (watch.Interface, error) {
return s.Watch(ctx, options)
}
func (s *storage) GetCluster(ctx api.Context, name string) (*federation.Cluster, error) {
obj, err := s.Get(ctx, name)
if err != nil {
return nil, err
}
return obj.(*federation.Cluster), nil
}
func (s *storage) CreateCluster(ctx api.Context, cluster *federation.Cluster) error {
_, err := s.Create(ctx, cluster)
return err
}
func (s *storage) UpdateCluster(ctx api.Context, cluster *federation.Cluster) error {
_, _, err := s.Update(ctx, cluster)
return err
}
func (s *storage) DeleteCluster(ctx api.Context, name string) error {
_, err := s.Delete(ctx, name, nil)
return err
}

View File

@ -0,0 +1,115 @@
/*
Copyright 2016 The Kubernetes Authors 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 cluster
import (
"fmt"
"k8s.io/kubernetes/federation/apis/federation"
"k8s.io/kubernetes/federation/apis/federation/validation"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/validation/field"
)
type clusterStrategy struct {
runtime.ObjectTyper
api.NameGenerator
}
var Strategy = clusterStrategy{api.Scheme, api.SimpleNameGenerator}
func (clusterStrategy) NamespaceScoped() bool {
return false
}
func ClusterToSelectableFields(cluster *federation.Cluster) fields.Set {
return generic.ObjectMetaFieldsSet(cluster.ObjectMeta, false)
}
func MatchCluster(label labels.Selector, field fields.Selector) generic.Matcher {
return &generic.SelectionPredicate{
Label: label,
Field: field,
GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) {
cluster, ok := obj.(*federation.Cluster)
if !ok {
return nil, nil, fmt.Errorf("given object is not a cluster.")
}
return labels.Set(cluster.ObjectMeta.Labels), ClusterToSelectableFields(cluster), nil
},
}
}
// PrepareForCreate clears fields that are not allowed to be set by end users on creation.
func (clusterStrategy) PrepareForCreate(obj runtime.Object) {
cluster := obj.(*federation.Cluster)
cluster.Status = federation.ClusterStatus{}
}
// Validate validates a new cluster.
func (clusterStrategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList {
cluster := obj.(*federation.Cluster)
return validation.ValidateCluster(cluster)
}
// Canonicalize normalizes the object after validation.
func (clusterStrategy) Canonicalize(obj runtime.Object) {
}
// AllowCreateOnUpdate is false for cluster.
func (clusterStrategy) AllowCreateOnUpdate() bool {
return false
}
// PrepareForUpdate clears fields that are not allowed to be set by end users on update.
func (clusterStrategy) PrepareForUpdate(obj, old runtime.Object) {
cluster := obj.(*federation.Cluster)
oldCluster := old.(*federation.Cluster)
cluster.Status = oldCluster.Status
}
// ValidateUpdate is the default update validation for an end user.
func (clusterStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList {
return validation.ValidateClusterUpdate(obj.(*federation.Cluster), old.(*federation.Cluster))
}
func (clusterStrategy) AllowUnconditionalUpdate() bool {
return true
}
type clusterStatusStrategy struct {
clusterStrategy
}
var StatusStrategy = clusterStatusStrategy{Strategy}
func (clusterStatusStrategy) PrepareForCreate(obj runtime.Object) {
_ = obj.(*federation.Cluster)
}
func (clusterStatusStrategy) PrepareForUpdate(obj, old runtime.Object) {
cluster := obj.(*federation.Cluster)
oldCluster := old.(*federation.Cluster)
cluster.Spec = oldCluster.Spec
}
// ValidateUpdate is the default update validation for an end user.
func (clusterStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList {
return validation.ValidateClusterStatusUpdate(obj.(*federation.Cluster), old.(*federation.Cluster))
}

View File

@ -0,0 +1,165 @@
/*
Copyright 2016 The Kubernetes Authors 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 cluster
import (
"testing"
"k8s.io/kubernetes/federation/apis/federation"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"reflect"
)
func validNewCluster() *federation.Cluster {
return &federation.Cluster{
ObjectMeta: api.ObjectMeta{
Name: "foo",
ResourceVersion: "4",
Labels: map[string]string{
"name": "foo",
},
},
Spec: federation.ClusterSpec{
ServerAddressByClientCIDRs: []unversioned.ServerAddressByClientCIDR{
{
ClientCIDR: "0.0.0.0/0",
ServerAddress: "localhost:8888",
},
},
},
Status: federation.ClusterStatus{
Conditions: []federation.ClusterCondition{
{Type: federation.ClusterReady, Status: api.ConditionTrue},
},
},
}
}
func invalidNewCluster() *federation.Cluster {
return &federation.Cluster{
ObjectMeta: api.ObjectMeta{
Name: "foo2",
ResourceVersion: "5",
},
Spec: federation.ClusterSpec{
Credential: "bar",
},
Status: federation.ClusterStatus{
Conditions: []federation.ClusterCondition{
{Type: federation.ClusterReady, Status: api.ConditionFalse},
},
},
}
}
func TestClusterStrategy(t *testing.T) {
ctx := api.NewDefaultContext()
if Strategy.NamespaceScoped() {
t.Errorf("Cluster should not be namespace scoped")
}
if Strategy.AllowCreateOnUpdate() {
t.Errorf("Cluster should not allow create on update")
}
cluster := validNewCluster()
Strategy.PrepareForCreate(cluster)
if len(cluster.Status.Conditions) != 0 {
t.Errorf("Cluster should not allow setting conditions on create")
}
errs := Strategy.Validate(ctx, cluster)
if len(errs) != 0 {
t.Errorf("Unexpected error validating %v", errs)
}
invalidCluster := invalidNewCluster()
Strategy.PrepareForUpdate(invalidCluster, cluster)
if reflect.DeepEqual(invalidCluster.Spec, cluster.Spec) ||
!reflect.DeepEqual(invalidCluster.Status, cluster.Status) {
t.Error("Only spec is expected being changed")
}
errs = Strategy.ValidateUpdate(ctx, invalidCluster, cluster)
if len(errs) == 0 {
t.Errorf("Expected a validation error")
}
if cluster.ResourceVersion != "4" {
t.Errorf("Incoming resource version on update should not be mutated")
}
}
func TestClusterStatusStrategy(t *testing.T) {
ctx := api.NewDefaultContext()
if StatusStrategy.NamespaceScoped() {
t.Errorf("Cluster should not be namespace scoped")
}
if StatusStrategy.AllowCreateOnUpdate() {
t.Errorf("Cluster should not allow create on update")
}
cluster := validNewCluster()
invalidCluster := invalidNewCluster()
StatusStrategy.PrepareForUpdate(cluster, invalidCluster)
if !reflect.DeepEqual(invalidCluster.Spec, cluster.Spec) ||
reflect.DeepEqual(invalidCluster.Status, cluster.Status) {
t.Logf("== cluster.Spec: %v\n", cluster.Spec)
t.Logf("== cluster.Status: %v\n", cluster.Status)
t.Logf("== invalidCluster.Spec: %v\n", cluster.Spec)
t.Logf("== invalidCluster.Spec: %v\n", cluster.Status)
t.Error("Only spec is expected being changed")
}
errs := Strategy.ValidateUpdate(ctx, invalidCluster, cluster)
if len(errs) == 0 {
t.Errorf("Expected a validation error")
}
if cluster.ResourceVersion != "4" {
t.Errorf("Incoming resource version on update should not be mutated")
}
}
func TestMatchCluster(t *testing.T) {
testFieldMap := map[bool][]fields.Set{
true: {
{"metadata.name": "foo"},
},
false: {
{"foo": "bar"},
},
}
for expectedResult, fieldSet := range testFieldMap {
for _, field := range fieldSet {
m := MatchCluster(labels.Everything(), field.AsSelector())
_, matchesSingle := m.MatchesSingle()
if e, a := expectedResult, matchesSingle; e != a {
t.Errorf("%+v: expected %v, got %v", fieldSet, e, a)
}
}
}
}
func TestSelectableFieldLabelConversions(t *testing.T) {
apitesting.TestSelectableFieldLabelConversionsOfKind(t,
testapi.Federation.GroupVersion().String(),
"Cluster",
labels.Set(ClusterToSelectableFields(&federation.Cluster{})),
nil,
)
}

View File

@ -58,7 +58,7 @@ KUBE_GOVERALLS_BIN=${KUBE_GOVERALLS_BIN:-}
# Lists of API Versions of each groups that should be tested, groups are
# separated by comma, lists are separated by semicolon. e.g.,
# "v1,compute/v1alpha1,experimental/v1alpha2;v1,compute/v2,experimental/v1alpha3"
KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1,extensions/v1beta1,metrics/v1alpha1;v1,autoscaling/v1,batch/v1,extensions/v1beta1,apps/v1alpha1,metrics/v1alpha1"}
KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1,extensions/v1beta1,metrics/v1alpha1,federation/v1alpha1;v1,autoscaling/v1,batch/v1,extensions/v1beta1,apps/v1alpha1,metrics/v1alpha1,federation/v1alpha1"}
# once we have multiple group supports
# Run tests with the standard (registry) and a custom etcd prefix
# (kubernetes.io/registry).

View File

@ -42,6 +42,7 @@ function prereqs() {
--volume "${REPO_DIR:-${KUBE_ROOT}}/Godeps/_workspace/src:/go/src/${KUBE_GO_PACKAGE}/Godeps/_workspace/src"
--volume "${REPO_DIR:-${KUBE_ROOT}}/hack:/go/src/${KUBE_GO_PACKAGE}/hack"
--volume "${REPO_DIR:-${KUBE_ROOT}}/pkg:/go/src/${KUBE_GO_PACKAGE}/pkg"
--volume "${REPO_DIR:-${KUBE_ROOT}}/federation:/go/src/${KUBE_GO_PACKAGE}/federation"
--volume "${REPO_DIR:-${KUBE_ROOT}}/third_party:/go/src/${KUBE_GO_PACKAGE}/third_party"
--volume /etc/localtime:/etc/localtime:ro
--volumes-from "${KUBE_BUILD_DATA_CONTAINER_NAME}"

View File

@ -23,6 +23,7 @@ import (
"reflect"
"strings"
"k8s.io/kubernetes/federation/apis/federation"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/unversioned"
@ -33,6 +34,7 @@ import (
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/runtime"
_ "k8s.io/kubernetes/federation/apis/federation/install"
_ "k8s.io/kubernetes/pkg/api/install"
_ "k8s.io/kubernetes/pkg/apis/apps/install"
_ "k8s.io/kubernetes/pkg/apis/autoscaling/install"
@ -49,6 +51,7 @@ var (
Batch TestGroup
Extensions TestGroup
Apps TestGroup
Federation TestGroup
)
type TestGroup struct {
@ -132,12 +135,20 @@ func init() {
internalTypes: api.Scheme.KnownTypes(extensions.SchemeGroupVersion),
}
}
if _, ok := Groups[federation.GroupName]; !ok {
Groups[federation.GroupName] = TestGroup{
externalGroupVersion: unversioned.GroupVersion{Group: federation.GroupName, Version: registered.GroupOrDie(federation.GroupName).GroupVersion.Version},
internalGroupVersion: federation.SchemeGroupVersion,
internalTypes: api.Scheme.KnownTypes(federation.SchemeGroupVersion),
}
}
Default = Groups[api.GroupName]
Autoscaling = Groups[autoscaling.GroupName]
Batch = Groups[batch.GroupName]
Apps = Groups[apps.GroupName]
Extensions = Groups[extensions.GroupName]
Federation = Groups[federation.GroupName]
}
func (g TestGroup) ContentConfig() (string, *unversioned.GroupVersion, runtime.Codec) {

View File

@ -105,6 +105,12 @@ func DeepCopy_unversioned_ListMeta(in ListMeta, out *ListMeta, c *conversion.Clo
return nil
}
func DeepCopy_unversioned_ServerAddressByClientCIDR(in ServerAddressByClientCIDR, out *ServerAddressByClientCIDR, c *conversion.Cloner) error {
out.ClientCIDR = in.ClientCIDR
out.ServerAddress = in.ServerAddress
return nil
}
func DeepCopy_unversioned_Time(in Time, out *Time, c *conversion.Cloner) error {
if newVal, err := c.DeepCopy(in.Time); err != nil {
return err