mirror of https://github.com/k3s-io/k3s
commit
1b0cf281e5
|
@ -2050,24 +2050,6 @@ func deepCopy_api_TCPSocketAction(in TCPSocketAction, out *TCPSocketAction, c *c
|
|||
return nil
|
||||
}
|
||||
|
||||
func deepCopy_api_ThirdPartyResourceData(in ThirdPartyResourceData, out *ThirdPartyResourceData, c *conversion.Cloner) error {
|
||||
if err := deepCopy_api_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := deepCopy_api_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Data != nil {
|
||||
out.Data = make([]uint8, len(in.Data))
|
||||
for i := range in.Data {
|
||||
out.Data[i] = in.Data[i]
|
||||
}
|
||||
} else {
|
||||
out.Data = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func deepCopy_api_TypeMeta(in TypeMeta, out *TypeMeta, c *conversion.Cloner) error {
|
||||
out.Kind = in.Kind
|
||||
out.APIVersion = in.APIVersion
|
||||
|
@ -2354,7 +2336,6 @@ func init() {
|
|||
deepCopy_api_StatusCause,
|
||||
deepCopy_api_StatusDetails,
|
||||
deepCopy_api_TCPSocketAction,
|
||||
deepCopy_api_ThirdPartyResourceData,
|
||||
deepCopy_api_TypeMeta,
|
||||
deepCopy_api_Volume,
|
||||
deepCopy_api_VolumeMount,
|
||||
|
|
|
@ -2279,22 +2279,6 @@ func convert_api_TCPSocketAction_To_v1_TCPSocketAction(in *api.TCPSocketAction,
|
|||
return nil
|
||||
}
|
||||
|
||||
func convert_api_ThirdPartyResourceData_To_v1_ThirdPartyResourceData(in *api.ThirdPartyResourceData, out *ThirdPartyResourceData, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*api.ThirdPartyResourceData))(in)
|
||||
}
|
||||
if err := convert_api_TypeMeta_To_v1_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := convert_api_ObjectMeta_To_v1_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Data, &out.Data, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func convert_api_TypeMeta_To_v1_TypeMeta(in *api.TypeMeta, out *TypeMeta, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*api.TypeMeta))(in)
|
||||
|
@ -4697,22 +4681,6 @@ func convert_v1_TCPSocketAction_To_api_TCPSocketAction(in *TCPSocketAction, out
|
|||
return nil
|
||||
}
|
||||
|
||||
func convert_v1_ThirdPartyResourceData_To_api_ThirdPartyResourceData(in *ThirdPartyResourceData, out *api.ThirdPartyResourceData, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*ThirdPartyResourceData))(in)
|
||||
}
|
||||
if err := convert_v1_TypeMeta_To_api_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := convert_v1_ObjectMeta_To_api_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Data, &out.Data, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func convert_v1_TypeMeta_To_api_TypeMeta(in *TypeMeta, out *api.TypeMeta, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*TypeMeta))(in)
|
||||
|
@ -4977,7 +4945,6 @@ func init() {
|
|||
convert_api_StatusDetails_To_v1_StatusDetails,
|
||||
convert_api_Status_To_v1_Status,
|
||||
convert_api_TCPSocketAction_To_v1_TCPSocketAction,
|
||||
convert_api_ThirdPartyResourceData_To_v1_ThirdPartyResourceData,
|
||||
convert_api_TypeMeta_To_v1_TypeMeta,
|
||||
convert_api_VolumeMount_To_v1_VolumeMount,
|
||||
convert_api_VolumeSource_To_v1_VolumeSource,
|
||||
|
@ -5095,7 +5062,6 @@ func init() {
|
|||
convert_v1_StatusDetails_To_api_StatusDetails,
|
||||
convert_v1_Status_To_api_Status,
|
||||
convert_v1_TCPSocketAction_To_api_TCPSocketAction,
|
||||
convert_v1_ThirdPartyResourceData_To_api_ThirdPartyResourceData,
|
||||
convert_v1_TypeMeta_To_api_TypeMeta,
|
||||
convert_v1_VolumeMount_To_api_VolumeMount,
|
||||
convert_v1_VolumeSource_To_api_VolumeSource,
|
||||
|
|
|
@ -2055,24 +2055,6 @@ func deepCopy_v1_TCPSocketAction(in TCPSocketAction, out *TCPSocketAction, c *co
|
|||
return nil
|
||||
}
|
||||
|
||||
func deepCopy_v1_ThirdPartyResourceData(in ThirdPartyResourceData, out *ThirdPartyResourceData, c *conversion.Cloner) error {
|
||||
if err := deepCopy_v1_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := deepCopy_v1_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Data != nil {
|
||||
out.Data = make([]uint8, len(in.Data))
|
||||
for i := range in.Data {
|
||||
out.Data[i] = in.Data[i]
|
||||
}
|
||||
} else {
|
||||
out.Data = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func deepCopy_v1_TypeMeta(in TypeMeta, out *TypeMeta, c *conversion.Cloner) error {
|
||||
out.Kind = in.Kind
|
||||
out.APIVersion = in.APIVersion
|
||||
|
@ -2356,7 +2338,6 @@ func init() {
|
|||
deepCopy_v1_StatusCause,
|
||||
deepCopy_v1_StatusDetails,
|
||||
deepCopy_v1_TCPSocketAction,
|
||||
deepCopy_v1_ThirdPartyResourceData,
|
||||
deepCopy_v1_TypeMeta,
|
||||
deepCopy_v1_Volume,
|
||||
deepCopy_v1_VolumeMount,
|
||||
|
|
|
@ -25,6 +25,11 @@ import (
|
|||
|
||||
func addDefaultingFuncs() {
|
||||
api.Scheme.AddDefaultingFuncs(
|
||||
func(obj *APIVersion) {
|
||||
if len(obj.APIGroup) == 0 {
|
||||
obj.APIGroup = "experimental"
|
||||
}
|
||||
},
|
||||
func(obj *ReplicationController) {
|
||||
var labels map[string]string
|
||||
if obj.Spec.Template != nil {
|
||||
|
|
|
@ -248,6 +248,9 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||
|
||||
var ctxFn ContextFunc
|
||||
ctxFn = func(req *restful.Request) api.Context {
|
||||
if context == nil {
|
||||
return api.NewContext()
|
||||
}
|
||||
if ctx, ok := context.Get(req.Request); ok {
|
||||
return ctx
|
||||
}
|
||||
|
|
|
@ -309,7 +309,7 @@ func createHandler(r rest.NamedCreater, scope RequestScope, typer runtime.Object
|
|||
return
|
||||
}
|
||||
|
||||
if admit.Handles(admission.Create) {
|
||||
if admit != nil && admit.Handles(admission.Create) {
|
||||
userInfo, _ := api.UserFrom(ctx)
|
||||
|
||||
err = admit.Admit(admission.NewAttributesRecord(obj, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, userInfo))
|
||||
|
@ -481,7 +481,7 @@ func UpdateResource(r rest.Updater, scope RequestScope, typer runtime.ObjectType
|
|||
return
|
||||
}
|
||||
|
||||
if admit.Handles(admission.Update) {
|
||||
if admit != nil && admit.Handles(admission.Update) {
|
||||
userInfo, _ := api.UserFrom(ctx)
|
||||
|
||||
err = admit.Admit(admission.NewAttributesRecord(obj, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, userInfo))
|
||||
|
@ -546,7 +546,7 @@ func DeleteResource(r rest.GracefulDeleter, checkBody bool, scope RequestScope,
|
|||
}
|
||||
}
|
||||
|
||||
if admit.Handles(admission.Delete) {
|
||||
if admit != nil && admit.Handles(admission.Delete) {
|
||||
userInfo, _ := api.UserFrom(ctx)
|
||||
|
||||
err = admit.Admit(admission.NewAttributesRecord(nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Delete, userInfo))
|
||||
|
|
|
@ -1076,6 +1076,44 @@ func deepCopy_expapi_ThirdPartyResource(in ThirdPartyResource, out *ThirdPartyRe
|
|||
return nil
|
||||
}
|
||||
|
||||
func deepCopy_expapi_ThirdPartyResourceData(in ThirdPartyResourceData, out *ThirdPartyResourceData, c *conversion.Cloner) error {
|
||||
if err := deepCopy_api_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := deepCopy_api_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Data != nil {
|
||||
out.Data = make([]uint8, len(in.Data))
|
||||
for i := range in.Data {
|
||||
out.Data[i] = in.Data[i]
|
||||
}
|
||||
} else {
|
||||
out.Data = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func deepCopy_expapi_ThirdPartyResourceDataList(in ThirdPartyResourceDataList, out *ThirdPartyResourceDataList, c *conversion.Cloner) error {
|
||||
if err := deepCopy_api_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := deepCopy_api_ListMeta(in.ListMeta, &out.ListMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Items != nil {
|
||||
out.Items = make([]ThirdPartyResourceData, len(in.Items))
|
||||
for i := range in.Items {
|
||||
if err := deepCopy_expapi_ThirdPartyResourceData(in.Items[i], &out.Items[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func deepCopy_expapi_ThirdPartyResourceList(in ThirdPartyResourceList, out *ThirdPartyResourceList, c *conversion.Cloner) error {
|
||||
if err := deepCopy_api_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
|
@ -1176,6 +1214,8 @@ func init() {
|
|||
deepCopy_expapi_ScaleStatus,
|
||||
deepCopy_expapi_SubresourceReference,
|
||||
deepCopy_expapi_ThirdPartyResource,
|
||||
deepCopy_expapi_ThirdPartyResourceData,
|
||||
deepCopy_expapi_ThirdPartyResourceDataList,
|
||||
deepCopy_expapi_ThirdPartyResourceList,
|
||||
deepCopy_util_IntOrString,
|
||||
deepCopy_util_Time,
|
||||
|
|
|
@ -38,6 +38,8 @@ func addKnownTypes() {
|
|||
&ThirdPartyResourceList{},
|
||||
&DaemonList{},
|
||||
&Daemon{},
|
||||
&ThirdPartyResourceData{},
|
||||
&ThirdPartyResourceDataList{},
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -51,3 +53,5 @@ func (*ThirdPartyResource) IsAnAPIObject() {}
|
|||
func (*ThirdPartyResourceList) IsAnAPIObject() {}
|
||||
func (*Daemon) IsAnAPIObject() {}
|
||||
func (*DaemonList) IsAnAPIObject() {}
|
||||
func (*ThirdPartyResourceData) IsAnAPIObject() {}
|
||||
func (*ThirdPartyResourceDataList) IsAnAPIObject() {}
|
||||
|
|
|
@ -318,3 +318,10 @@ type DaemonList struct {
|
|||
|
||||
Items []Daemon `json:"items"`
|
||||
}
|
||||
|
||||
type ThirdPartyResourceDataList struct {
|
||||
api.TypeMeta `json:",inline"`
|
||||
api.ListMeta `json:"metadata,omitempty" description:"standard list metadata; see http://docs.k8s.io/api-conventions.md#metadata"`
|
||||
|
||||
Items []ThirdPartyResourceData `json:"items" description:"items is a list of third party objects"`
|
||||
}
|
||||
|
|
|
@ -1888,6 +1888,45 @@ func convert_expapi_ThirdPartyResource_To_v1_ThirdPartyResource(in *expapi.Third
|
|||
return nil
|
||||
}
|
||||
|
||||
func convert_expapi_ThirdPartyResourceData_To_v1_ThirdPartyResourceData(in *expapi.ThirdPartyResourceData, out *ThirdPartyResourceData, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*expapi.ThirdPartyResourceData))(in)
|
||||
}
|
||||
if err := convert_api_TypeMeta_To_v1_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := convert_api_ObjectMeta_To_v1_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Data, &out.Data, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func convert_expapi_ThirdPartyResourceDataList_To_v1_ThirdPartyResourceDataList(in *expapi.ThirdPartyResourceDataList, out *ThirdPartyResourceDataList, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*expapi.ThirdPartyResourceDataList))(in)
|
||||
}
|
||||
if err := convert_api_TypeMeta_To_v1_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := convert_api_ListMeta_To_v1_ListMeta(&in.ListMeta, &out.ListMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Items != nil {
|
||||
out.Items = make([]ThirdPartyResourceData, len(in.Items))
|
||||
for i := range in.Items {
|
||||
if err := convert_expapi_ThirdPartyResourceData_To_v1_ThirdPartyResourceData(&in.Items[i], &out.Items[i], s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func convert_expapi_ThirdPartyResourceList_To_v1_ThirdPartyResourceList(in *expapi.ThirdPartyResourceList, out *ThirdPartyResourceList, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*expapi.ThirdPartyResourceList))(in)
|
||||
|
@ -2237,6 +2276,45 @@ func convert_v1_ThirdPartyResource_To_expapi_ThirdPartyResource(in *ThirdPartyRe
|
|||
return nil
|
||||
}
|
||||
|
||||
func convert_v1_ThirdPartyResourceData_To_expapi_ThirdPartyResourceData(in *ThirdPartyResourceData, out *expapi.ThirdPartyResourceData, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*ThirdPartyResourceData))(in)
|
||||
}
|
||||
if err := convert_v1_TypeMeta_To_api_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := convert_v1_ObjectMeta_To_api_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Data, &out.Data, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func convert_v1_ThirdPartyResourceDataList_To_expapi_ThirdPartyResourceDataList(in *ThirdPartyResourceDataList, out *expapi.ThirdPartyResourceDataList, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*ThirdPartyResourceDataList))(in)
|
||||
}
|
||||
if err := convert_v1_TypeMeta_To_api_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := convert_v1_ListMeta_To_api_ListMeta(&in.ListMeta, &out.ListMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Items != nil {
|
||||
out.Items = make([]expapi.ThirdPartyResourceData, len(in.Items))
|
||||
for i := range in.Items {
|
||||
if err := convert_v1_ThirdPartyResourceData_To_expapi_ThirdPartyResourceData(&in.Items[i], &out.Items[i], s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func convert_v1_ThirdPartyResourceList_To_expapi_ThirdPartyResourceList(in *ThirdPartyResourceList, out *expapi.ThirdPartyResourceList, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*ThirdPartyResourceList))(in)
|
||||
|
@ -2318,6 +2396,8 @@ func init() {
|
|||
convert_expapi_ScaleStatus_To_v1_ScaleStatus,
|
||||
convert_expapi_Scale_To_v1_Scale,
|
||||
convert_expapi_SubresourceReference_To_v1_SubresourceReference,
|
||||
convert_expapi_ThirdPartyResourceDataList_To_v1_ThirdPartyResourceDataList,
|
||||
convert_expapi_ThirdPartyResourceData_To_v1_ThirdPartyResourceData,
|
||||
convert_expapi_ThirdPartyResourceList_To_v1_ThirdPartyResourceList,
|
||||
convert_expapi_ThirdPartyResource_To_v1_ThirdPartyResource,
|
||||
convert_v1_APIVersion_To_expapi_APIVersion,
|
||||
|
@ -2372,6 +2452,8 @@ func init() {
|
|||
convert_v1_SecurityContext_To_api_SecurityContext,
|
||||
convert_v1_SubresourceReference_To_expapi_SubresourceReference,
|
||||
convert_v1_TCPSocketAction_To_api_TCPSocketAction,
|
||||
convert_v1_ThirdPartyResourceDataList_To_expapi_ThirdPartyResourceDataList,
|
||||
convert_v1_ThirdPartyResourceData_To_expapi_ThirdPartyResourceData,
|
||||
convert_v1_ThirdPartyResourceList_To_expapi_ThirdPartyResourceList,
|
||||
convert_v1_ThirdPartyResource_To_expapi_ThirdPartyResource,
|
||||
convert_v1_TypeMeta_To_api_TypeMeta,
|
||||
|
|
|
@ -1098,6 +1098,44 @@ func deepCopy_v1_ThirdPartyResource(in ThirdPartyResource, out *ThirdPartyResour
|
|||
return nil
|
||||
}
|
||||
|
||||
func deepCopy_v1_ThirdPartyResourceData(in ThirdPartyResourceData, out *ThirdPartyResourceData, c *conversion.Cloner) error {
|
||||
if err := deepCopy_v1_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := deepCopy_v1_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Data != nil {
|
||||
out.Data = make([]uint8, len(in.Data))
|
||||
for i := range in.Data {
|
||||
out.Data[i] = in.Data[i]
|
||||
}
|
||||
} else {
|
||||
out.Data = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func deepCopy_v1_ThirdPartyResourceDataList(in ThirdPartyResourceDataList, out *ThirdPartyResourceDataList, c *conversion.Cloner) error {
|
||||
if err := deepCopy_v1_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := deepCopy_v1_ListMeta(in.ListMeta, &out.ListMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Items != nil {
|
||||
out.Items = make([]ThirdPartyResourceData, len(in.Items))
|
||||
for i := range in.Items {
|
||||
if err := deepCopy_v1_ThirdPartyResourceData(in.Items[i], &out.Items[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func deepCopy_v1_ThirdPartyResourceList(in ThirdPartyResourceList, out *ThirdPartyResourceList, c *conversion.Cloner) error {
|
||||
if err := deepCopy_v1_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
|
@ -1198,6 +1236,8 @@ func init() {
|
|||
deepCopy_v1_ScaleStatus,
|
||||
deepCopy_v1_SubresourceReference,
|
||||
deepCopy_v1_ThirdPartyResource,
|
||||
deepCopy_v1_ThirdPartyResourceData,
|
||||
deepCopy_v1_ThirdPartyResourceDataList,
|
||||
deepCopy_v1_ThirdPartyResourceList,
|
||||
deepCopy_util_IntOrString,
|
||||
deepCopy_util_Time,
|
||||
|
|
|
@ -42,6 +42,8 @@ func addKnownTypes() {
|
|||
&ThirdPartyResourceList{},
|
||||
&DaemonList{},
|
||||
&Daemon{},
|
||||
&ThirdPartyResourceData{},
|
||||
&ThirdPartyResourceDataList{},
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -55,3 +57,5 @@ func (*ThirdPartyResource) IsAnAPIObject() {}
|
|||
func (*ThirdPartyResourceList) IsAnAPIObject() {}
|
||||
func (*Daemon) IsAnAPIObject() {}
|
||||
func (*DaemonList) IsAnAPIObject() {}
|
||||
func (*ThirdPartyResourceData) IsAnAPIObject() {}
|
||||
func (*ThirdPartyResourceDataList) IsAnAPIObject() {}
|
||||
|
|
|
@ -318,3 +318,10 @@ type DaemonList struct {
|
|||
// Items is a list of daemons.
|
||||
Items []Daemon `json:"items"`
|
||||
}
|
||||
|
||||
type ThirdPartyResourceDataList struct {
|
||||
v1.TypeMeta `json:",inline"`
|
||||
v1.ListMeta `json:"metadata,omitempty" description:"standard list metadata; see http://docs.k8s.io/api-conventions.md#metadata"`
|
||||
|
||||
Items []ThirdPartyResourceData `json:"items" description:"items is a list of third party objects"`
|
||||
}
|
||||
|
|
|
@ -255,3 +255,15 @@ func ValidateDeployment(obj *expapi.Deployment) errs.ValidationErrorList {
|
|||
allErrs = append(allErrs, ValidateDeploymentSpec(&obj.Spec).Prefix("spec")...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func ValidateThirdPartyResourceDataUpdate(old, update *expapi.ThirdPartyResourceData) errs.ValidationErrorList {
|
||||
return ValidateThirdPartyResourceData(update)
|
||||
}
|
||||
|
||||
func ValidateThirdPartyResourceData(obj *expapi.ThirdPartyResourceData) errs.ValidationErrorList {
|
||||
allErrs := errs.ValidationErrorList{}
|
||||
if len(obj.Name) == 0 {
|
||||
allErrs = append(allErrs, errs.NewFieldInvalid("name", obj.Name, "name must be non-empty"))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/auth/authorizer"
|
||||
"k8s.io/kubernetes/pkg/auth/handlers"
|
||||
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||
"k8s.io/kubernetes/pkg/expapi"
|
||||
explatest "k8s.io/kubernetes/pkg/expapi/latest"
|
||||
"k8s.io/kubernetes/pkg/fields"
|
||||
"k8s.io/kubernetes/pkg/healthz"
|
||||
|
@ -71,6 +72,8 @@ import (
|
|||
ipallocator "k8s.io/kubernetes/pkg/registry/service/ipallocator"
|
||||
serviceaccountetcd "k8s.io/kubernetes/pkg/registry/serviceaccount/etcd"
|
||||
thirdpartyresourceetcd "k8s.io/kubernetes/pkg/registry/thirdpartyresource/etcd"
|
||||
"k8s.io/kubernetes/pkg/registry/thirdpartyresourcedata"
|
||||
thirdpartyresourcedataetcd "k8s.io/kubernetes/pkg/registry/thirdpartyresourcedata/etcd"
|
||||
"k8s.io/kubernetes/pkg/storage"
|
||||
etcdstorage "k8s.io/kubernetes/pkg/storage/etcd"
|
||||
"k8s.io/kubernetes/pkg/tools"
|
||||
|
@ -233,6 +236,9 @@ type Master struct {
|
|||
lastSync int64 // Seconds since Epoch
|
||||
lastSyncMetric prometheus.GaugeFunc
|
||||
clock util.Clock
|
||||
|
||||
// storage for third party objects
|
||||
thirdPartyStorage storage.Interface
|
||||
}
|
||||
|
||||
// NewEtcdStorage returns a storage.Interface for the provided arguments or an error if the version
|
||||
|
@ -765,6 +771,52 @@ func (m *Master) api_v1() *apiserver.APIGroupVersion {
|
|||
return version
|
||||
}
|
||||
|
||||
func (m *Master) InstallThirdPartyAPI(rsrc *expapi.ThirdPartyResource) error {
|
||||
kind, group, err := thirdpartyresourcedata.ExtractApiGroupAndKind(rsrc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
thirdparty := m.thirdpartyapi(group, kind, rsrc.Versions[0].Name)
|
||||
if err := thirdparty.InstallREST(m.handlerContainer); err != nil {
|
||||
glog.Fatalf("Unable to setup thirdparty api: %v", err)
|
||||
}
|
||||
thirdPartyPrefix := "/thirdparty/" + group + "/"
|
||||
apiserver.AddApiWebService(m.handlerContainer, thirdPartyPrefix, []string{rsrc.Versions[0].Name})
|
||||
thirdPartyRequestInfoResolver := &apiserver.APIRequestInfoResolver{APIPrefixes: util.NewStringSet(strings.TrimPrefix(group, "/")), RestMapper: thirdparty.Mapper}
|
||||
apiserver.InstallServiceErrorHandler(m.handlerContainer, thirdPartyRequestInfoResolver, []string{thirdparty.Version})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Master) thirdpartyapi(group, kind, version string) *apiserver.APIGroupVersion {
|
||||
resourceStorage := thirdpartyresourcedataetcd.NewREST(m.thirdPartyStorage, group, kind)
|
||||
|
||||
apiRoot := "/thirdparty/" + group + "/"
|
||||
|
||||
storage := map[string]rest.Storage{
|
||||
strings.ToLower(kind) + "s": resourceStorage,
|
||||
}
|
||||
|
||||
return &apiserver.APIGroupVersion{
|
||||
Root: apiRoot,
|
||||
|
||||
Creater: thirdpartyresourcedata.NewObjectCreator(version, api.Scheme),
|
||||
Convertor: api.Scheme,
|
||||
Typer: api.Scheme,
|
||||
|
||||
Mapper: thirdpartyresourcedata.NewMapper(explatest.RESTMapper, kind, version),
|
||||
Codec: explatest.Codec,
|
||||
Linker: explatest.SelfLinker,
|
||||
Storage: storage,
|
||||
Version: version,
|
||||
|
||||
Admit: m.admissionControl,
|
||||
Context: m.requestContextMapper,
|
||||
|
||||
ProxyDialerFn: m.dialer,
|
||||
MinRequestTimeout: m.minRequestTimeout,
|
||||
}
|
||||
}
|
||||
|
||||
// expapi returns the resources and codec for the experimental api
|
||||
func (m *Master) expapi(c *Config) *apiserver.APIGroupVersion {
|
||||
controllerStorage := expcontrolleretcd.NewStorage(c.ExpDatabaseStorage)
|
||||
|
|
|
@ -17,15 +17,24 @@ limitations under the License.
|
|||
package master
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/latest"
|
||||
"k8s.io/kubernetes/pkg/expapi"
|
||||
explatest "k8s.io/kubernetes/pkg/expapi/latest"
|
||||
"k8s.io/kubernetes/pkg/registry/registrytest"
|
||||
etcdstorage "k8s.io/kubernetes/pkg/storage/etcd"
|
||||
"k8s.io/kubernetes/pkg/tools"
|
||||
"k8s.io/kubernetes/pkg/tools/etcdtest"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
)
|
||||
|
||||
func TestGetServersToValidate(t *testing.T) {
|
||||
|
@ -73,3 +82,311 @@ func TestFindExternalAddress(t *testing.T) {
|
|||
t.Errorf("expected findExternalAddress to fail on a node with missing ip information")
|
||||
}
|
||||
}
|
||||
|
||||
var versionsToTest = []string{"v1", "v3"}
|
||||
|
||||
type Foo struct {
|
||||
api.TypeMeta `json:",inline"`
|
||||
api.ObjectMeta `json:"metadata,omitempty" description:"standard object metadata"`
|
||||
|
||||
SomeField string `json:"someField"`
|
||||
OtherField int `json:"otherField"`
|
||||
}
|
||||
|
||||
type FooList struct {
|
||||
api.TypeMeta `json:",inline"`
|
||||
api.ListMeta `json:"metadata,omitempty" description:"standard list metadata; see http://docs.k8s.io/api-conventions.md#metadata"`
|
||||
|
||||
items []Foo `json:"items"`
|
||||
}
|
||||
|
||||
func initThirdParty(t *testing.T, version string) (*tools.FakeEtcdClient, *httptest.Server) {
|
||||
master := &Master{}
|
||||
api := &expapi.ThirdPartyResource{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "foo.company.com",
|
||||
},
|
||||
Versions: []expapi.APIVersion{
|
||||
{
|
||||
APIGroup: "group",
|
||||
Name: version,
|
||||
},
|
||||
},
|
||||
}
|
||||
master.handlerContainer = restful.NewContainer()
|
||||
|
||||
fakeClient := tools.NewFakeEtcdClient(t)
|
||||
fakeClient.Machines = []string{"http://machine1:4001", "http://machine2", "http://machine3:4003"}
|
||||
master.thirdPartyStorage = etcdstorage.NewEtcdStorage(fakeClient, explatest.Codec, etcdtest.PathPrefix())
|
||||
|
||||
if err := master.InstallThirdPartyAPI(api); err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
server := httptest.NewServer(master.handlerContainer.ServeMux)
|
||||
return fakeClient, server
|
||||
}
|
||||
|
||||
func TestInstallThirdPartyAPIList(t *testing.T) {
|
||||
for _, version := range versionsToTest {
|
||||
testInstallThirdPartyAPIListVersion(t, version)
|
||||
}
|
||||
}
|
||||
|
||||
func testInstallThirdPartyAPIListVersion(t *testing.T, version string) {
|
||||
fakeClient, server := initThirdParty(t, version)
|
||||
defer server.Close()
|
||||
|
||||
fakeClient.ExpectNotFoundGet(etcdtest.PathPrefix() + "/ThirdPartyResourceData/company.com/foos/default")
|
||||
|
||||
resp, err := http.Get(server.URL + "/thirdparty/company.com/" + version + "/namespaces/default/foos")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
t.Errorf("unexpected status: %v", resp)
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
list := FooList{}
|
||||
if err := json.Unmarshal(data, &list); err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func encodeToThirdParty(name string, obj interface{}) ([]byte, error) {
|
||||
serial, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
thirdPartyData := expapi.ThirdPartyResourceData{
|
||||
ObjectMeta: api.ObjectMeta{Name: name},
|
||||
Data: serial,
|
||||
}
|
||||
return latest.Codec.Encode(&thirdPartyData)
|
||||
}
|
||||
|
||||
func storeToEtcd(fakeClient *tools.FakeEtcdClient, path, name string, obj interface{}) error {
|
||||
data, err := encodeToThirdParty(name, obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = fakeClient.Set(etcdtest.PathPrefix()+path, string(data), 0)
|
||||
return err
|
||||
}
|
||||
|
||||
func decodeResponse(resp *http.Response, obj interface{}) error {
|
||||
defer resp.Body.Close()
|
||||
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, obj); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestInstallThirdPartyAPIGet(t *testing.T) {
|
||||
for _, version := range versionsToTest {
|
||||
testInstallThirdPartyAPIGetVersion(t, version)
|
||||
}
|
||||
}
|
||||
|
||||
func testInstallThirdPartyAPIGetVersion(t *testing.T, version string) {
|
||||
fakeClient, server := initThirdParty(t, version)
|
||||
defer server.Close()
|
||||
|
||||
expectedObj := Foo{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "test",
|
||||
},
|
||||
TypeMeta: api.TypeMeta{
|
||||
Kind: "Foo",
|
||||
APIVersion: version,
|
||||
},
|
||||
SomeField: "test field",
|
||||
OtherField: 10,
|
||||
}
|
||||
if err := storeToEtcd(fakeClient, "/ThirdPartyResourceData/company.com/foos/default/test", "test", expectedObj); err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
t.FailNow()
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := http.Get(server.URL + "/thirdparty/company.com/" + version + "/namespaces/default/foos/test")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
t.Errorf("unexpected status: %v", resp)
|
||||
}
|
||||
item := Foo{}
|
||||
if err := decodeResponse(resp, &item); err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(item, expectedObj) {
|
||||
t.Errorf("expected:\n%v\nsaw:\n%v\n", expectedObj, item)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInstallThirdPartyAPIPost(t *testing.T) {
|
||||
for _, version := range versionsToTest {
|
||||
testInstallThirdPartyAPIPostForVersion(t, version)
|
||||
}
|
||||
}
|
||||
|
||||
func testInstallThirdPartyAPIPostForVersion(t *testing.T, version string) {
|
||||
fakeClient, server := initThirdParty(t, version)
|
||||
defer server.Close()
|
||||
|
||||
inputObj := Foo{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "test",
|
||||
},
|
||||
TypeMeta: api.TypeMeta{
|
||||
Kind: "Foo",
|
||||
APIVersion: version,
|
||||
},
|
||||
SomeField: "test field",
|
||||
OtherField: 10,
|
||||
}
|
||||
data, err := json.Marshal(inputObj)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v")
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := http.Post(server.URL+"/thirdparty/company.com/"+version+"/namespaces/default/foos", "application/json", bytes.NewBuffer(data))
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusCreated {
|
||||
t.Errorf("unexpected status: %v", resp)
|
||||
}
|
||||
|
||||
item := Foo{}
|
||||
if err := decodeResponse(resp, &item); err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(item, inputObj) {
|
||||
t.Errorf("expected:\n%v\nsaw:\n%v\n", inputObj, item)
|
||||
}
|
||||
|
||||
etcdResp, err := fakeClient.Get(etcdtest.PathPrefix()+"/ThirdPartyResourceData/company.com/foos/default/test", false, false)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
t.FailNow()
|
||||
}
|
||||
obj, err := explatest.Codec.Decode([]byte(etcdResp.Node.Value))
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
thirdPartyObj, ok := obj.(*expapi.ThirdPartyResourceData)
|
||||
if !ok {
|
||||
t.Errorf("unexpected object: %v", obj)
|
||||
}
|
||||
item = Foo{}
|
||||
if err := json.Unmarshal(thirdPartyObj.Data, &item); err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(item, inputObj) {
|
||||
t.Errorf("expected:\n%v\nsaw:\n%v\n", inputObj, item)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInstallThirdPartyAPIDelete(t *testing.T) {
|
||||
for _, version := range versionsToTest {
|
||||
testInstallThirdPartyAPIDeleteVersion(t, version)
|
||||
}
|
||||
}
|
||||
|
||||
func testInstallThirdPartyAPIDeleteVersion(t *testing.T, version string) {
|
||||
fakeClient, server := initThirdParty(t, version)
|
||||
defer server.Close()
|
||||
|
||||
expectedObj := Foo{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "test",
|
||||
},
|
||||
TypeMeta: api.TypeMeta{
|
||||
Kind: "Foo",
|
||||
},
|
||||
SomeField: "test field",
|
||||
OtherField: 10,
|
||||
}
|
||||
if err := storeToEtcd(fakeClient, "/ThirdPartyResourceData/company.com/foos/default/test", "test", expectedObj); err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
t.FailNow()
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := http.Get(server.URL + "/thirdparty/company.com/" + version + "/namespaces/default/foos/test")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
t.Errorf("unexpected status: %v", resp)
|
||||
}
|
||||
|
||||
item := Foo{}
|
||||
if err := decodeResponse(resp, &item); err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(item, expectedObj) {
|
||||
t.Errorf("expected:\n%v\nsaw:\n%v\n", expectedObj, item)
|
||||
}
|
||||
|
||||
resp, err = httpDelete(server.URL + "/thirdparty/company.com/" + version + "/namespaces/default/foos/test")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
t.Errorf("unexpected status: %v", resp)
|
||||
}
|
||||
|
||||
resp, err = http.Get(server.URL + "/thirdparty/company.com/" + version + "/namespaces/default/foos/test")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusNotFound {
|
||||
t.Errorf("unexpected status: %v", resp)
|
||||
}
|
||||
expectDeletedKeys := []string{etcdtest.PathPrefix() + "/ThirdPartyResourceData/company.com/foos/default/test"}
|
||||
if !reflect.DeepEqual(fakeClient.DeletedKeys, expectDeletedKeys) {
|
||||
t.Errorf("unexpected deleted keys: %v", fakeClient.DeletedKeys)
|
||||
}
|
||||
}
|
||||
|
||||
func httpDelete(url string) (*http.Response, error) {
|
||||
req, err := http.NewRequest("DELETE", url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client := &http.Client{}
|
||||
return client.Do(req)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,274 @@
|
|||
/*
|
||||
Copyright 2015 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 thirdpartyresourcedata
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
"k8s.io/kubernetes/pkg/expapi"
|
||||
"k8s.io/kubernetes/pkg/expapi/latest"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
type thirdPartyResourceDataMapper struct {
|
||||
mapper meta.RESTMapper
|
||||
kind string
|
||||
version string
|
||||
}
|
||||
|
||||
func (t *thirdPartyResourceDataMapper) GroupForResource(resource string) (string, error) {
|
||||
return t.mapper.GroupForResource(resource)
|
||||
}
|
||||
|
||||
func (t *thirdPartyResourceDataMapper) RESTMapping(kind string, versions ...string) (*meta.RESTMapping, error) {
|
||||
if len(versions) != 1 {
|
||||
return nil, fmt.Errorf("unexpected set of versions: %v", versions)
|
||||
}
|
||||
if versions[0] != t.version {
|
||||
return nil, fmt.Errorf("unknown version %s expected %s", versions[0], t.version)
|
||||
}
|
||||
if kind != "ThirdPartyResourceData" {
|
||||
return nil, fmt.Errorf("unknown kind %s expected %s", kind, t.kind)
|
||||
}
|
||||
mapping, err := t.mapper.RESTMapping("ThirdPartyResourceData", latest.Version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mapping.Codec = NewCodec(mapping.Codec, t.kind)
|
||||
return mapping, nil
|
||||
}
|
||||
|
||||
func (t *thirdPartyResourceDataMapper) AliasesForResource(resource string) ([]string, bool) {
|
||||
return t.mapper.AliasesForResource(resource)
|
||||
}
|
||||
|
||||
func (t *thirdPartyResourceDataMapper) ResourceSingularizer(resource string) (singular string, err error) {
|
||||
return t.mapper.ResourceSingularizer(resource)
|
||||
}
|
||||
|
||||
func (t *thirdPartyResourceDataMapper) VersionAndKindForResource(resource string) (defaultVersion, kind string, err error) {
|
||||
return t.mapper.VersionAndKindForResource(resource)
|
||||
}
|
||||
|
||||
func NewMapper(mapper meta.RESTMapper, kind, version string) meta.RESTMapper {
|
||||
return &thirdPartyResourceDataMapper{
|
||||
mapper: mapper,
|
||||
kind: kind,
|
||||
version: version,
|
||||
}
|
||||
}
|
||||
|
||||
type thirdPartyResourceDataCodec struct {
|
||||
delegate runtime.Codec
|
||||
kind string
|
||||
}
|
||||
|
||||
func NewCodec(codec runtime.Codec, kind string) runtime.Codec {
|
||||
return &thirdPartyResourceDataCodec{codec, kind}
|
||||
}
|
||||
|
||||
func (t *thirdPartyResourceDataCodec) populate(objIn *expapi.ThirdPartyResourceData, data []byte) error {
|
||||
var obj interface{}
|
||||
if err := json.Unmarshal(data, &obj); err != nil {
|
||||
fmt.Printf("Invalid JSON:\n%s\n", string(data))
|
||||
return err
|
||||
}
|
||||
mapObj, ok := obj.(map[string]interface{})
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected object: %#v", obj)
|
||||
}
|
||||
return t.populateFromObject(objIn, mapObj, data)
|
||||
}
|
||||
|
||||
func (t *thirdPartyResourceDataCodec) populateFromObject(objIn *expapi.ThirdPartyResourceData, mapObj map[string]interface{}, data []byte) error {
|
||||
kind, ok := mapObj["kind"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected object for kind: %#v", mapObj["kind"])
|
||||
}
|
||||
if kind != t.kind {
|
||||
return fmt.Errorf("unexpected kind: %s, expected: %s", kind, t.kind)
|
||||
}
|
||||
|
||||
metadata, ok := mapObj["metadata"].(map[string]interface{})
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected object for metadata: %#v", mapObj["metadata"])
|
||||
}
|
||||
|
||||
if resourceVersion, ok := metadata["resourceVersion"]; ok {
|
||||
resourceVersionStr, ok := resourceVersion.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected object for resourceVersion: %v", resourceVersion)
|
||||
}
|
||||
|
||||
objIn.ResourceVersion = resourceVersionStr
|
||||
}
|
||||
|
||||
name, ok := metadata["name"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected object for name: %#v", metadata)
|
||||
}
|
||||
|
||||
if labels, ok := metadata["labels"]; ok {
|
||||
labelMap, ok := labels.(map[string]interface{})
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected object for labels: %v", labelMap)
|
||||
}
|
||||
for key, value := range labelMap {
|
||||
valueStr, ok := value.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected label: %v", value)
|
||||
}
|
||||
if objIn.Labels == nil {
|
||||
objIn.Labels = map[string]string{}
|
||||
}
|
||||
objIn.Labels[key] = valueStr
|
||||
}
|
||||
}
|
||||
|
||||
objIn.Name = name
|
||||
objIn.Data = data
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *thirdPartyResourceDataCodec) Decode(data []byte) (runtime.Object, error) {
|
||||
result := &expapi.ThirdPartyResourceData{}
|
||||
if err := t.populate(result, data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (t *thirdPartyResourceDataCodec) DecodeToVersion(data []byte, version string) (runtime.Object, error) {
|
||||
// TODO: this is hacky, there must be a better way...
|
||||
obj, err := t.Decode(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
objData, err := t.delegate.Encode(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return t.delegate.DecodeToVersion(objData, version)
|
||||
}
|
||||
|
||||
func (t *thirdPartyResourceDataCodec) DecodeInto(data []byte, obj runtime.Object) error {
|
||||
thirdParty, ok := obj.(*expapi.ThirdPartyResourceData)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected object: %#v", obj)
|
||||
}
|
||||
return t.populate(thirdParty, data)
|
||||
}
|
||||
|
||||
func (t *thirdPartyResourceDataCodec) DecodeIntoWithSpecifiedVersionKind(data []byte, obj runtime.Object, version, kind string) error {
|
||||
thirdParty, ok := obj.(*expapi.ThirdPartyResourceData)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected object: %#v", obj)
|
||||
}
|
||||
|
||||
if kind != "ThirdPartyResourceData" {
|
||||
return fmt.Errorf("unexpeceted kind: %s", kind)
|
||||
}
|
||||
|
||||
var dataObj interface{}
|
||||
if err := json.Unmarshal(data, &dataObj); err != nil {
|
||||
return err
|
||||
}
|
||||
mapObj, ok := dataObj.(map[string]interface{})
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpcted object: %#v", dataObj)
|
||||
}
|
||||
if kindObj, found := mapObj["kind"]; !found {
|
||||
mapObj["kind"] = kind
|
||||
} else {
|
||||
kindStr, ok := kindObj.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected object for 'kind': %v", kindObj)
|
||||
}
|
||||
if kindStr != t.kind {
|
||||
return fmt.Errorf("kind doesn't match, expecting: %s, got %s", kind, kindStr)
|
||||
}
|
||||
}
|
||||
if versionObj, found := mapObj["apiVersion"]; !found {
|
||||
mapObj["apiVersion"] = version
|
||||
} else {
|
||||
versionStr, ok := versionObj.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected object for 'apiVersion': %v", versionObj)
|
||||
}
|
||||
if versionStr != version {
|
||||
return fmt.Errorf("version doesn't match, expecting: %s, got %s", version, versionStr)
|
||||
}
|
||||
}
|
||||
|
||||
if err := t.populate(thirdParty, data); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
const template = `{
|
||||
"kind": "%s",
|
||||
"items": [ %s ]
|
||||
}`
|
||||
|
||||
func (t *thirdPartyResourceDataCodec) Encode(obj runtime.Object) (data []byte, err error) {
|
||||
switch obj := obj.(type) {
|
||||
case *expapi.ThirdPartyResourceData:
|
||||
return obj.Data, nil
|
||||
case *expapi.ThirdPartyResourceDataList:
|
||||
// TODO: There must be a better way to do this...
|
||||
buff := &bytes.Buffer{}
|
||||
dataStrings := make([]string, len(obj.Items))
|
||||
for ix := range obj.Items {
|
||||
dataStrings[ix] = string(obj.Items[ix].Data)
|
||||
}
|
||||
fmt.Fprintf(buff, template, t.kind+"List", strings.Join(dataStrings, ","))
|
||||
return buff.Bytes(), nil
|
||||
case *api.Status:
|
||||
return t.delegate.Encode(obj)
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected object to encode: %#v", obj)
|
||||
}
|
||||
}
|
||||
|
||||
func NewObjectCreator(version string, delegate runtime.ObjectCreater) runtime.ObjectCreater {
|
||||
return &thirdPartyResourceDataCreator{version, delegate}
|
||||
}
|
||||
|
||||
type thirdPartyResourceDataCreator struct {
|
||||
version string
|
||||
delegate runtime.ObjectCreater
|
||||
}
|
||||
|
||||
func (t *thirdPartyResourceDataCreator) New(version, kind string) (out runtime.Object, err error) {
|
||||
if t.version != version {
|
||||
return nil, fmt.Errorf("unknown version %s for kind %s", version, kind)
|
||||
}
|
||||
switch kind {
|
||||
case "ThirdPartyResourceData":
|
||||
return &expapi.ThirdPartyResourceData{}, nil
|
||||
case "ThirdPartyResourceDataList":
|
||||
return &expapi.ThirdPartyResourceDataList{}, nil
|
||||
default:
|
||||
return t.delegate.New(latest.Version, kind)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
Copyright 2015 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 thirdpartyresourcedata
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/expapi"
|
||||
)
|
||||
|
||||
type Foo struct {
|
||||
api.TypeMeta `json:",inline"`
|
||||
api.ObjectMeta `json:"metadata,omitempty" description:"standard object metadata"`
|
||||
|
||||
SomeField string `json:"someField"`
|
||||
OtherField int `json:"otherField"`
|
||||
}
|
||||
|
||||
type FooList struct {
|
||||
api.TypeMeta `json:",inline"`
|
||||
api.ListMeta `json:"metadata,omitempty" description:"standard list metadata; see http://docs.k8s.io/api-conventions.md#metadata"`
|
||||
|
||||
items []Foo `json:"items"`
|
||||
}
|
||||
|
||||
func TestCodec(t *testing.T) {
|
||||
tests := []struct {
|
||||
obj *Foo
|
||||
expectErr bool
|
||||
name string
|
||||
}{
|
||||
{
|
||||
obj: &Foo{ObjectMeta: api.ObjectMeta{Name: "bar"}},
|
||||
expectErr: true,
|
||||
name: "missing kind",
|
||||
},
|
||||
{
|
||||
obj: &Foo{ObjectMeta: api.ObjectMeta{Name: "bar"}, TypeMeta: api.TypeMeta{Kind: "Foo"}},
|
||||
name: "basic",
|
||||
},
|
||||
{
|
||||
obj: &Foo{ObjectMeta: api.ObjectMeta{Name: "bar", ResourceVersion: "baz"}, TypeMeta: api.TypeMeta{Kind: "Foo"}},
|
||||
name: "resource version",
|
||||
},
|
||||
{
|
||||
obj: &Foo{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "bar",
|
||||
ResourceVersion: "baz",
|
||||
Labels: map[string]string{"foo": "bar", "baz": "blah"},
|
||||
},
|
||||
TypeMeta: api.TypeMeta{Kind: "Foo"},
|
||||
},
|
||||
name: "labels",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
codec := thirdPartyResourceDataCodec{kind: "Foo"}
|
||||
data, err := json.Marshal(test.obj)
|
||||
if err != nil {
|
||||
t.Errorf("[%s] unexpected error: %v", test.name, err)
|
||||
continue
|
||||
}
|
||||
obj, err := codec.Decode(data)
|
||||
if err != nil && !test.expectErr {
|
||||
t.Errorf("[%s] unexpected error: %v", test.name, err)
|
||||
continue
|
||||
}
|
||||
if test.expectErr {
|
||||
if err == nil {
|
||||
t.Errorf("[%s] unexpected non-error", test.name)
|
||||
}
|
||||
continue
|
||||
}
|
||||
rsrcObj, ok := obj.(*expapi.ThirdPartyResourceData)
|
||||
if !ok {
|
||||
t.Errorf("[%s] unexpected object: %v", test.name, obj)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(rsrcObj.ObjectMeta, test.obj.ObjectMeta) {
|
||||
t.Errorf("[%s]\nexpected\n%v\nsaw\n%v\n", test.name, rsrcObj.ObjectMeta, test.obj.ObjectMeta)
|
||||
}
|
||||
var output Foo
|
||||
if err := json.Unmarshal(rsrcObj.Data, &output); err != nil {
|
||||
t.Errorf("[%s] unexpected error: %v", test.name, err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(&output, test.obj) {
|
||||
t.Errorf("[%s]\nexpected\n%v\nsaw\n%v\n", test.name, test.obj, &output)
|
||||
}
|
||||
|
||||
data, err = codec.Encode(rsrcObj)
|
||||
if err != nil {
|
||||
t.Errorf("[%s] unexpected error: %v", test.name, err)
|
||||
}
|
||||
|
||||
var output2 Foo
|
||||
if err := json.Unmarshal(data, &output2); err != nil {
|
||||
t.Errorf("[%s] unexpected error: %v", test.name, err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(&output2, test.obj) {
|
||||
t.Errorf("[%s]\nexpected\n%v\nsaw\n%v\n", test.name, test.obj, &output2)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
Copyright 2015 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 thirdpartyresourcedata provides Registry interface and its REST
|
||||
// implementation for storing ThirdPartyResourceData api objects.
|
||||
package thirdpartyresourcedata
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
Copyright 2015 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 (
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/expapi"
|
||||
"k8s.io/kubernetes/pkg/fields"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
"k8s.io/kubernetes/pkg/registry/generic"
|
||||
etcdgeneric "k8s.io/kubernetes/pkg/registry/generic/etcd"
|
||||
"k8s.io/kubernetes/pkg/registry/thirdpartyresourcedata"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/storage"
|
||||
)
|
||||
|
||||
// REST implements a RESTStorage for ThirdPartyResourceDatas against etcd
|
||||
type REST struct {
|
||||
*etcdgeneric.Etcd
|
||||
}
|
||||
|
||||
// NewREST returns a registry which will store ThirdPartyResourceData in the given helper
|
||||
func NewREST(s storage.Interface, group, kind string) *REST {
|
||||
prefix := "/ThirdPartyResourceData/" + group + "/" + strings.ToLower(kind) + "s"
|
||||
|
||||
store := &etcdgeneric.Etcd{
|
||||
NewFunc: func() runtime.Object { return &expapi.ThirdPartyResourceData{} },
|
||||
NewListFunc: func() runtime.Object { return &expapi.ThirdPartyResourceDataList{} },
|
||||
KeyRootFunc: func(ctx api.Context) string {
|
||||
return etcdgeneric.NamespaceKeyRootFunc(ctx, prefix)
|
||||
},
|
||||
KeyFunc: func(ctx api.Context, id string) (string, error) {
|
||||
return etcdgeneric.NamespaceKeyFunc(ctx, prefix, id)
|
||||
},
|
||||
ObjectNameFunc: func(obj runtime.Object) (string, error) {
|
||||
return obj.(*expapi.ThirdPartyResourceData).Name, nil
|
||||
},
|
||||
PredicateFunc: func(label labels.Selector, field fields.Selector) generic.Matcher {
|
||||
return thirdpartyresourcedata.Matcher(label, field)
|
||||
},
|
||||
EndpointName: "thirdpartyresourcedata",
|
||||
CreateStrategy: thirdpartyresourcedata.Strategy,
|
||||
UpdateStrategy: thirdpartyresourcedata.Strategy,
|
||||
|
||||
Storage: s,
|
||||
}
|
||||
|
||||
return &REST{store}
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
Copyright 2015 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/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/rest/resttest"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
"k8s.io/kubernetes/pkg/expapi"
|
||||
"k8s.io/kubernetes/pkg/expapi/v1"
|
||||
"k8s.io/kubernetes/pkg/fields"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/storage"
|
||||
etcdstorage "k8s.io/kubernetes/pkg/storage/etcd"
|
||||
"k8s.io/kubernetes/pkg/tools"
|
||||
"k8s.io/kubernetes/pkg/tools/etcdtest"
|
||||
|
||||
"github.com/coreos/go-etcd/etcd"
|
||||
)
|
||||
|
||||
var scheme *runtime.Scheme
|
||||
var codec runtime.Codec
|
||||
|
||||
func init() {
|
||||
// Ensure that expapi/v1 packege is used, so that it will get initialized and register HorizontalPodAutoscaler object.
|
||||
_ = v1.ThirdPartyResourceData{}
|
||||
}
|
||||
|
||||
func newStorage(t *testing.T) (*REST, *tools.FakeEtcdClient, storage.Interface) {
|
||||
fakeEtcdClient := tools.NewFakeEtcdClient(t)
|
||||
fakeEtcdClient.TestIndex = true
|
||||
etcdStorage := etcdstorage.NewEtcdStorage(fakeEtcdClient, testapi.Codec(), etcdtest.PathPrefix())
|
||||
storage := NewREST(etcdStorage, "foo", "bar")
|
||||
return storage, fakeEtcdClient, etcdStorage
|
||||
}
|
||||
|
||||
func validNewThirdPartyResourceData(name string) *expapi.ThirdPartyResourceData {
|
||||
return &expapi.ThirdPartyResourceData{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Data: []byte("foobarbaz"),
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
storage, fakeEtcdClient, _ := newStorage(t)
|
||||
test := resttest.New(t, storage, fakeEtcdClient.SetError)
|
||||
rsrc := validNewThirdPartyResourceData("foo")
|
||||
rsrc.ObjectMeta = api.ObjectMeta{}
|
||||
test.TestCreate(
|
||||
// valid
|
||||
rsrc,
|
||||
// invalid
|
||||
&expapi.ThirdPartyResourceData{},
|
||||
)
|
||||
}
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
storage, fakeEtcdClient, _ := newStorage(t)
|
||||
test := resttest.New(t, storage, fakeEtcdClient.SetError)
|
||||
key, err := storage.KeyFunc(test.TestContext(), "foo")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
key = etcdtest.AddPrefix(key)
|
||||
fakeEtcdClient.ExpectNotFoundGet(key)
|
||||
fakeEtcdClient.ChangeIndex = 2
|
||||
rsrc := validNewThirdPartyResourceData("foo")
|
||||
existing := validNewThirdPartyResourceData("exists")
|
||||
existing.Namespace = test.TestNamespace()
|
||||
obj, err := storage.Create(test.TestContext(), existing)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create object: %v", err)
|
||||
}
|
||||
older := obj.(*expapi.ThirdPartyResourceData)
|
||||
older.ResourceVersion = "1"
|
||||
test.TestUpdate(
|
||||
rsrc,
|
||||
existing,
|
||||
older,
|
||||
)
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
storage, fakeEtcdClient, _ := newStorage(t)
|
||||
test := resttest.New(t, storage, fakeEtcdClient.SetError)
|
||||
rsrc := validNewThirdPartyResourceData("foo")
|
||||
test.TestGet(rsrc)
|
||||
}
|
||||
|
||||
func TestEmptyList(t *testing.T) {
|
||||
ctx := api.NewDefaultContext()
|
||||
registry, fakeClient, _ := newStorage(t)
|
||||
fakeClient.ChangeIndex = 1
|
||||
key := registry.KeyRootFunc(ctx)
|
||||
key = etcdtest.AddPrefix(key)
|
||||
fakeClient.Data[key] = tools.EtcdResponseWithError{
|
||||
R: &etcd.Response{},
|
||||
E: fakeClient.NewError(tools.EtcdErrorCodeNotFound),
|
||||
}
|
||||
rsrcList, err := registry.List(ctx, labels.Everything(), fields.Everything())
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if len(rsrcList.(*expapi.ThirdPartyResourceDataList).Items) != 0 {
|
||||
t.Errorf("Unexpected non-zero autoscaler list: %#v", rsrcList)
|
||||
}
|
||||
if rsrcList.(*expapi.ThirdPartyResourceDataList).ResourceVersion != "1" {
|
||||
t.Errorf("Unexpected resource version: %#v", rsrcList)
|
||||
}
|
||||
}
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
ctx := api.NewDefaultContext()
|
||||
registry, fakeClient, _ := newStorage(t)
|
||||
fakeClient.ChangeIndex = 1
|
||||
key := registry.KeyRootFunc(ctx)
|
||||
key = etcdtest.AddPrefix(key)
|
||||
fakeClient.Data[key] = tools.EtcdResponseWithError{
|
||||
R: &etcd.Response{
|
||||
Node: &etcd.Node{
|
||||
Nodes: []*etcd.Node{
|
||||
{
|
||||
Value: runtime.EncodeOrDie(testapi.Codec(), &expapi.ThirdPartyResourceData{
|
||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||
}),
|
||||
},
|
||||
{
|
||||
Value: runtime.EncodeOrDie(testapi.Codec(), &expapi.ThirdPartyResourceData{
|
||||
ObjectMeta: api.ObjectMeta{Name: "bar"},
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
obj, err := registry.List(ctx, labels.Everything(), fields.Everything())
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
}
|
||||
rsrcList := obj.(*expapi.ThirdPartyResourceDataList)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if len(rsrcList.Items) != 2 {
|
||||
t.Errorf("Unexpected ThirdPartyResourceData list: %#v", rsrcList)
|
||||
}
|
||||
if rsrcList.Items[0].Name != "foo" {
|
||||
t.Errorf("Unexpected ThirdPartyResourceData: %#v", rsrcList.Items[0])
|
||||
}
|
||||
if rsrcList.Items[1].Name != "bar" {
|
||||
t.Errorf("Unexpected ThirdPartyResourceData: %#v", rsrcList.Items[1])
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
Copyright 2015 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 thirdpartyresourcedata
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/rest"
|
||||
"k8s.io/kubernetes/pkg/expapi"
|
||||
"k8s.io/kubernetes/pkg/fields"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
)
|
||||
|
||||
// Registry is an interface implemented by things that know how to store ThirdPartyResourceData objects.
|
||||
type Registry interface {
|
||||
// ListThirdPartyResourceData obtains a list of ThirdPartyResourceData having labels which match selector.
|
||||
ListThirdPartyResourceData(ctx api.Context, selector labels.Selector) (*expapi.ThirdPartyResourceDataList, error)
|
||||
// Watch for new/changed/deleted ThirdPartyResourceData
|
||||
WatchThirdPartyResourceData(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error)
|
||||
// Get a specific ThirdPartyResourceData
|
||||
GetThirdPartyResourceData(ctx api.Context, name string) (*expapi.ThirdPartyResourceData, error)
|
||||
// Create a ThirdPartyResourceData based on a specification.
|
||||
CreateThirdPartyResourceData(ctx api.Context, resource *expapi.ThirdPartyResourceData) (*expapi.ThirdPartyResourceData, error)
|
||||
// Update an existing ThirdPartyResourceData
|
||||
UpdateThirdPartyResourceData(ctx api.Context, resource *expapi.ThirdPartyResourceData) (*expapi.ThirdPartyResourceData, error)
|
||||
// Delete an existing ThirdPartyResourceData
|
||||
DeleteThirdPartyResourceData(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) ListThirdPartyResourceData(ctx api.Context, label labels.Selector) (*expapi.ThirdPartyResourceDataList, error) {
|
||||
obj, err := s.List(ctx, label, fields.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*expapi.ThirdPartyResourceDataList), nil
|
||||
}
|
||||
|
||||
func (s *storage) WatchThirdPartyResourceData(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) {
|
||||
return s.Watch(ctx, label, field, resourceVersion)
|
||||
}
|
||||
|
||||
func (s *storage) GetThirdPartyResourceData(ctx api.Context, name string) (*expapi.ThirdPartyResourceData, error) {
|
||||
obj, err := s.Get(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*expapi.ThirdPartyResourceData), nil
|
||||
}
|
||||
|
||||
func (s *storage) CreateThirdPartyResourceData(ctx api.Context, ThirdPartyResourceData *expapi.ThirdPartyResourceData) (*expapi.ThirdPartyResourceData, error) {
|
||||
obj, err := s.Create(ctx, ThirdPartyResourceData)
|
||||
return obj.(*expapi.ThirdPartyResourceData), err
|
||||
}
|
||||
|
||||
func (s *storage) UpdateThirdPartyResourceData(ctx api.Context, ThirdPartyResourceData *expapi.ThirdPartyResourceData) (*expapi.ThirdPartyResourceData, error) {
|
||||
obj, _, err := s.Update(ctx, ThirdPartyResourceData)
|
||||
return obj.(*expapi.ThirdPartyResourceData), err
|
||||
}
|
||||
|
||||
func (s *storage) DeleteThirdPartyResourceData(ctx api.Context, name string) error {
|
||||
_, err := s.Delete(ctx, name, nil)
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
Copyright 2015 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 thirdpartyresourcedata
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/rest"
|
||||
"k8s.io/kubernetes/pkg/expapi"
|
||||
"k8s.io/kubernetes/pkg/expapi/validation"
|
||||
"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/fielderrors"
|
||||
)
|
||||
|
||||
// strategy implements behavior for ThirdPartyResource objects
|
||||
type strategy struct {
|
||||
runtime.ObjectTyper
|
||||
api.NameGenerator
|
||||
}
|
||||
|
||||
// Strategy is the default logic that applies when creating and updating ThirdPartyResource
|
||||
// objects via the REST API.
|
||||
var Strategy = strategy{api.Scheme, api.SimpleNameGenerator}
|
||||
|
||||
var _ = rest.RESTCreateStrategy(Strategy)
|
||||
|
||||
var _ = rest.RESTUpdateStrategy(Strategy)
|
||||
|
||||
func (strategy) NamespaceScoped() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (strategy) PrepareForCreate(obj runtime.Object) {
|
||||
}
|
||||
|
||||
func (strategy) Validate(ctx api.Context, obj runtime.Object) fielderrors.ValidationErrorList {
|
||||
return validation.ValidateThirdPartyResourceData(obj.(*expapi.ThirdPartyResourceData))
|
||||
}
|
||||
|
||||
func (strategy) AllowCreateOnUpdate() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (strategy) PrepareForUpdate(obj, old runtime.Object) {
|
||||
}
|
||||
|
||||
func (strategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) fielderrors.ValidationErrorList {
|
||||
return validation.ValidateThirdPartyResourceDataUpdate(old.(*expapi.ThirdPartyResourceData), obj.(*expapi.ThirdPartyResourceData))
|
||||
}
|
||||
|
||||
func (strategy) AllowUnconditionalUpdate() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Matcher returns a generic matcher for a given label and field selector.
|
||||
func Matcher(label labels.Selector, field fields.Selector) generic.Matcher {
|
||||
return generic.MatcherFunc(func(obj runtime.Object) (bool, error) {
|
||||
sa, ok := obj.(*expapi.ThirdPartyResourceData)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("not a ThirdPartyResourceData")
|
||||
}
|
||||
fields := SelectableFields(sa)
|
||||
return label.Matches(labels.Set(sa.Labels)) && field.Matches(fields), nil
|
||||
})
|
||||
}
|
||||
|
||||
// SelectableFields returns a label set that can be used for filter selection
|
||||
func SelectableFields(obj *expapi.ThirdPartyResourceData) labels.Set {
|
||||
return labels.Set{}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
Copyright 2015 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 thirdpartyresourcedata
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/pkg/expapi"
|
||||
)
|
||||
|
||||
func convertToCamelCase(input string) string {
|
||||
result := ""
|
||||
toUpper := true
|
||||
for ix := range input {
|
||||
char := input[ix]
|
||||
if toUpper {
|
||||
result = result + string([]byte{(char - 32)})
|
||||
toUpper = false
|
||||
} else if char == '-' {
|
||||
toUpper = true
|
||||
} else {
|
||||
result = result + string([]byte{char})
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func ExtractApiGroupAndKind(rsrc *expapi.ThirdPartyResource) (kind string, group string, err error) {
|
||||
parts := strings.Split(rsrc.Name, ".")
|
||||
if len(parts) < 3 {
|
||||
return "", "", fmt.Errorf("unexpectedly short resource name: %s, expected at least <kind>.<domain>.<tld>", rsrc.Name)
|
||||
}
|
||||
return convertToCamelCase(parts[0]), strings.Join(parts[1:], "."), nil
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
Copyright 2015 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 thirdpartyresourcedata
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/expapi"
|
||||
)
|
||||
|
||||
func TestExtractAPIGroupAndKind(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
expectedKind string
|
||||
expectedGroup string
|
||||
expectErr bool
|
||||
}{
|
||||
{
|
||||
input: "foo.company.com",
|
||||
expectedKind: "Foo",
|
||||
expectedGroup: "company.com",
|
||||
},
|
||||
{
|
||||
input: "cron-tab.company.com",
|
||||
expectedKind: "CronTab",
|
||||
expectedGroup: "company.com",
|
||||
},
|
||||
{
|
||||
input: "foo",
|
||||
expectErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
kind, group, err := ExtractApiGroupAndKind(&expapi.ThirdPartyResource{ObjectMeta: api.ObjectMeta{Name: test.input}})
|
||||
if err != nil && !test.expectErr {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
continue
|
||||
}
|
||||
if err == nil && test.expectErr {
|
||||
t.Errorf("unexpected non-error")
|
||||
continue
|
||||
}
|
||||
if kind != test.expectedKind {
|
||||
t.Errorf("expected: %s, saw: %s", test.expectedKind, kind)
|
||||
}
|
||||
if group != test.expectedGroup {
|
||||
t.Errorf("expected: %s, saw: %s", test.expectedGroup, group)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue