diff --git a/cmd/kube-controller-manager/app/autoscaling.go b/cmd/kube-controller-manager/app/autoscaling.go index 76f80d9ae1..f53d65b05d 100644 --- a/cmd/kube-controller-manager/app/autoscaling.go +++ b/cmd/kube-controller-manager/app/autoscaling.go @@ -28,6 +28,7 @@ import ( "k8s.io/client-go/scale" "k8s.io/kubernetes/pkg/controller/podautoscaler" "k8s.io/kubernetes/pkg/controller/podautoscaler/metrics" + resourceclient "k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1beta1" "k8s.io/metrics/pkg/client/custom_metrics" "k8s.io/metrics/pkg/client/external_metrics" @@ -48,9 +49,19 @@ func startHPAController(ctx ControllerContext) (http.Handler, bool, error) { func startHPAControllerWithRESTClient(ctx ControllerContext) (http.Handler, bool, error) { clientConfig := ctx.ClientBuilder.ConfigOrDie("horizontal-pod-autoscaler") + hpaClient := ctx.ClientBuilder.ClientOrDie("horizontal-pod-autoscaler") + + apiVersionsGetter := custom_metrics.NewAvailableAPIsGetter(hpaClient.Discovery()) + // invalidate the discovery information roughly once per resync interval our API + // information is *at most* two resync intervals old. + go custom_metrics.PeriodicallyInvalidate( + apiVersionsGetter, + ctx.ComponentConfig.HPAController.HorizontalPodAutoscalerSyncPeriod.Duration, + ctx.Stop) + metricsClient := metrics.NewRESTMetricsClient( resourceclient.NewForConfigOrDie(clientConfig), - custom_metrics.NewForConfigOrDie(clientConfig), + custom_metrics.NewForConfig(clientConfig, ctx.RESTMapper, apiVersionsGetter), external_metrics.NewForConfigOrDie(clientConfig), ) return startHPAControllerWithMetricsClient(ctx, metricsClient) diff --git a/staging/src/k8s.io/metrics/Godeps/Godeps.json b/staging/src/k8s.io/metrics/Godeps/Godeps.json index 8a3032fd29..59a8e39a3d 100644 --- a/staging/src/k8s.io/metrics/Godeps/Godeps.json +++ b/staging/src/k8s.io/metrics/Godeps/Godeps.json @@ -90,6 +90,18 @@ "ImportPath": "github.com/peterbourgon/diskv", "Rev": "5f041e8faa004a95c88a202771f4cc3e991971e6" }, + { + "ImportPath": "github.com/pmezard/go-difflib/difflib", + "Rev": "d8ed2627bdf02c080bf22230dbb337003b7aba2d" + }, + { + "ImportPath": "github.com/stretchr/testify/assert", + "Rev": "c679ae2cc0cb27ec3293fea7e254e47386f05d69" + }, + { + "ImportPath": "github.com/stretchr/testify/require", + "Rev": "c679ae2cc0cb27ec3293fea7e254e47386f05d69" + }, { "ImportPath": "golang.org/x/crypto/ssh/terminal", "Rev": "de0752318171da717af4ce24d0a2e8626afaeb11" @@ -438,6 +450,10 @@ "ImportPath": "k8s.io/client-go/discovery", "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }, + { + "ImportPath": "k8s.io/client-go/discovery/cached", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, { "ImportPath": "k8s.io/client-go/discovery/fake", "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" diff --git a/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/register.go b/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/register.go index 091fcc483d..a44b8b410c 100644 --- a/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/register.go +++ b/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/register.go @@ -46,6 +46,7 @@ func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &MetricValue{}, &MetricValueList{}, + &MetricListOptions{}, ) return nil } diff --git a/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/types.go b/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/types.go index b426c01995..a39d5c460d 100644 --- a/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/types.go +++ b/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/types.go @@ -71,6 +71,22 @@ type MetricValue struct { // for all objects matching the given label selector const AllObjects = "*" +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// MetricListOptions is used to select metrics by their label selectors +type MetricListOptions struct { + metav1.TypeMeta `json:",inline"` + + // A selector to restrict the list of returned objects by their labels. + // Defaults to everything. + // +optional + LabelSelector string `json:"labelSelector,omitempty" protobuf:"bytes,1,opt,name=labelSelector"` + + // A selector to restrict the list of returned metrics by their labels + // +optional + MetricLabelSelector string `json:"metricLabelSelector,omitempty" protobuf:"bytes,2,opt,name=metricLabelSelector"` +} + // NOTE: ObjectReference is copied from k8s.io/kubernetes/pkg/api/types.go. We // cannot depend on k8s.io/kubernetes/pkg/api because that creates cyclic // dependency between k8s.io/metrics and k8s.io/kubernetes. We cannot depend on diff --git a/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1/generated.pb.go b/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1/generated.pb.go index 3191ebd3de..704c8cc634 100644 --- a/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1/generated.pb.go +++ b/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1/generated.pb.go @@ -25,6 +25,7 @@ limitations under the License. k8s.io/kubernetes/vendor/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1/generated.proto It has these top-level messages: + MetricListOptions MetricValue MetricValueList */ @@ -52,18 +53,49 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package +func (m *MetricListOptions) Reset() { *m = MetricListOptions{} } +func (*MetricListOptions) ProtoMessage() {} +func (*MetricListOptions) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{0} } + func (m *MetricValue) Reset() { *m = MetricValue{} } func (*MetricValue) ProtoMessage() {} -func (*MetricValue) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{0} } +func (*MetricValue) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{1} } func (m *MetricValueList) Reset() { *m = MetricValueList{} } func (*MetricValueList) ProtoMessage() {} -func (*MetricValueList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{1} } +func (*MetricValueList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{2} } func init() { + proto.RegisterType((*MetricListOptions)(nil), "k8s.io.metrics.pkg.apis.custom_metrics.v1beta1.MetricListOptions") proto.RegisterType((*MetricValue)(nil), "k8s.io.metrics.pkg.apis.custom_metrics.v1beta1.MetricValue") proto.RegisterType((*MetricValueList)(nil), "k8s.io.metrics.pkg.apis.custom_metrics.v1beta1.MetricValueList") } +func (m *MetricListOptions) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MetricListOptions) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.LabelSelector))) + i += copy(dAtA[i:], m.LabelSelector) + dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.MetricLabelSelector))) + i += copy(dAtA[i:], m.MetricLabelSelector) + return i, nil +} + func (m *MetricValue) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -190,6 +222,16 @@ func encodeVarintGenerated(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return offset + 1 } +func (m *MetricListOptions) Size() (n int) { + var l int + _ = l + l = len(m.LabelSelector) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.MetricLabelSelector) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + func (m *MetricValue) Size() (n int) { var l int _ = l @@ -238,6 +280,17 @@ func sovGenerated(x uint64) (n int) { func sozGenerated(x uint64) (n int) { return sovGenerated(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } +func (this *MetricListOptions) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&MetricListOptions{`, + `LabelSelector:` + fmt.Sprintf("%v", this.LabelSelector) + `,`, + `MetricLabelSelector:` + fmt.Sprintf("%v", this.MetricLabelSelector) + `,`, + `}`, + }, "") + return s +} func (this *MetricValue) String() string { if this == nil { return "nil" @@ -272,6 +325,114 @@ func valueToStringGenerated(v interface{}) string { pv := reflect.Indirect(rv).Interface() return fmt.Sprintf("*%v", pv) } +func (m *MetricListOptions) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MetricListOptions: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MetricListOptions: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LabelSelector", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.LabelSelector = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MetricLabelSelector", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MetricLabelSelector = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *MetricValue) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -715,41 +876,44 @@ func init() { } var fileDescriptorGenerated = []byte{ - // 566 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x93, 0x4f, 0x6f, 0xd3, 0x3e, - 0x18, 0xc7, 0x9b, 0xf5, 0xd7, 0xfd, 0x3a, 0x8f, 0x69, 0x2c, 0x17, 0xa2, 0x1d, 0xd2, 0x6a, 0x5c, - 0x0a, 0xd2, 0x6c, 0x6d, 0x20, 0x84, 0xc4, 0x2d, 0xe2, 0x82, 0xb4, 0x81, 0xc8, 0x26, 0x26, 0xf1, - 0x47, 0xe0, 0x38, 0x4f, 0x53, 0xd3, 0x26, 0x8e, 0x6c, 0xa7, 0xd3, 0x6e, 0xbc, 0x04, 0x5e, 0x56, - 0x8f, 0xe3, 0xb6, 0x53, 0x45, 0x83, 0x78, 0x1f, 0x28, 0x89, 0xd3, 0x76, 0x1b, 0x7f, 0xb6, 0x5b, - 0x6c, 0x3f, 0xdf, 0x8f, 0xbf, 0xcf, 0xf7, 0x71, 0xd0, 0xc9, 0xf0, 0xa9, 0xc2, 0x5c, 0x90, 0x61, - 0x16, 0x80, 0x4c, 0x40, 0x83, 0x22, 0x63, 0x48, 0x42, 0x21, 0x89, 0x39, 0x88, 0x41, 0x4b, 0xce, - 0x14, 0x49, 0x87, 0x11, 0xa1, 0x29, 0x57, 0x84, 0x65, 0x4a, 0x8b, 0xf8, 0x63, 0xbd, 0x3f, 0xde, - 0x0b, 0x40, 0xd3, 0x3d, 0x12, 0x41, 0x02, 0x92, 0x6a, 0x08, 0x71, 0x2a, 0x85, 0x16, 0x36, 0xae, - 0xf4, 0xd8, 0xd4, 0xe1, 0x74, 0x18, 0xe1, 0x42, 0x8f, 0x2f, 0xeb, 0xb1, 0xd1, 0x6f, 0xef, 0x46, - 0x5c, 0x0f, 0xb2, 0x00, 0x33, 0x11, 0x93, 0x48, 0x44, 0x82, 0x94, 0x98, 0x20, 0xeb, 0x97, 0xab, - 0x72, 0x51, 0x7e, 0x55, 0xf8, 0xed, 0x1d, 0x63, 0x8f, 0xa6, 0x9c, 0x30, 0x21, 0x81, 0x8c, 0xaf, - 0x59, 0xd8, 0x7e, 0xbc, 0xa8, 0x89, 0x29, 0x1b, 0xf0, 0x04, 0xe4, 0x59, 0xdd, 0x07, 0x91, 0xa0, - 0x44, 0x26, 0x19, 0xdc, 0x4a, 0xa5, 0x8a, 0x38, 0xe8, 0xef, 0xee, 0x22, 0x7f, 0x52, 0xc9, 0x2c, - 0xd1, 0x3c, 0xbe, 0x7e, 0xcd, 0x93, 0x7f, 0x09, 0x14, 0x1b, 0x40, 0x4c, 0xaf, 0xea, 0x76, 0x7e, - 0x36, 0xd1, 0xfa, 0x61, 0x99, 0xdd, 0x1b, 0x3a, 0xca, 0xc0, 0xee, 0xa3, 0xcd, 0x10, 0x14, 0x93, - 0x3c, 0x80, 0xf0, 0x55, 0xf0, 0x19, 0x98, 0x76, 0xac, 0xae, 0xd5, 0x5b, 0xdf, 0xbf, 0x5f, 0x4f, - 0x80, 0xa6, 0x1c, 0x17, 0x11, 0xe1, 0xf1, 0x1e, 0xae, 0x2a, 0x7c, 0xe8, 0x83, 0x84, 0x84, 0x81, - 0x77, 0x6f, 0x32, 0xed, 0x34, 0xf2, 0x69, 0x67, 0xf3, 0xf9, 0x65, 0x86, 0x7f, 0x15, 0x6a, 0xef, - 0x23, 0x54, 0x8d, 0xec, 0x25, 0x8d, 0xc1, 0x59, 0xe9, 0x5a, 0xbd, 0x35, 0xcf, 0x36, 0x6a, 0x74, - 0x38, 0x3f, 0xf1, 0x97, 0xaa, 0xec, 0x77, 0x68, 0xad, 0x68, 0x45, 0x69, 0x1a, 0xa7, 0x4e, 0xb3, - 0x74, 0xf5, 0x70, 0xc9, 0xd5, 0xbc, 0xef, 0xc5, 0xe3, 0x28, 0xe2, 0x2d, 0x7c, 0x1e, 0xf3, 0x18, - 0xbc, 0x2d, 0x83, 0x5f, 0x3b, 0xae, 0x21, 0xfe, 0x82, 0x67, 0x3f, 0x40, 0xab, 0xa7, 0x3c, 0x09, - 0xc5, 0xa9, 0xf3, 0x5f, 0xd7, 0xea, 0x35, 0xbd, 0xad, 0x7c, 0xda, 0xd9, 0x38, 0x29, 0x77, 0x8e, - 0x80, 0x89, 0x24, 0x54, 0xbe, 0x29, 0xb0, 0x8f, 0x50, 0x6b, 0x5c, 0x84, 0xe5, 0xb4, 0x4a, 0x0f, - 0xf8, 0x6f, 0x1e, 0x70, 0xfd, 0x30, 0xf0, 0xeb, 0x8c, 0x26, 0x9a, 0xeb, 0x33, 0x6f, 0xc3, 0xf8, - 0x68, 0x95, 0x89, 0xfb, 0x15, 0xcb, 0xfe, 0x80, 0xda, 0x0a, 0x46, 0xc0, 0xb4, 0x90, 0xce, 0x6a, - 0xc9, 0x7d, 0x74, 0xb3, 0xde, 0x0e, 0x68, 0x00, 0xa3, 0x23, 0x23, 0xf5, 0xee, 0xe4, 0xd3, 0x4e, - 0xbb, 0x5e, 0xf9, 0x73, 0xe4, 0xce, 0x37, 0x0b, 0x6d, 0x2e, 0xcd, 0xf9, 0x80, 0x2b, 0x6d, 0xbf, - 0x47, 0xed, 0x02, 0x12, 0x52, 0x4d, 0xcd, 0x90, 0xf1, 0x0d, 0xaf, 0xe4, 0x4a, 0x1f, 0x82, 0xa6, - 0xde, 0x5d, 0xd3, 0x4a, 0xbb, 0xde, 0xf1, 0xe7, 0x44, 0xfb, 0x13, 0x6a, 0x71, 0x0d, 0xb1, 0x72, - 0x56, 0xba, 0xcd, 0xde, 0xfa, 0xfe, 0xb3, 0x5b, 0xfe, 0xc1, 0x78, 0xc9, 0xed, 0x22, 0xb2, 0x17, - 0x05, 0xd1, 0xaf, 0xc0, 0xde, 0xee, 0x64, 0xe6, 0x36, 0xce, 0x67, 0x6e, 0xe3, 0x62, 0xe6, 0x36, - 0xbe, 0xe4, 0xae, 0x35, 0xc9, 0x5d, 0xeb, 0x3c, 0x77, 0xad, 0x8b, 0xdc, 0xb5, 0xbe, 0xe7, 0xae, - 0xf5, 0xf5, 0x87, 0xdb, 0x78, 0xfb, 0xbf, 0x01, 0xfe, 0x0a, 0x00, 0x00, 0xff, 0xff, 0xdb, 0xed, - 0x64, 0xfc, 0x9c, 0x04, 0x00, 0x00, + // 616 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0x4f, 0x4f, 0x14, 0x3f, + 0x1c, 0xc6, 0x77, 0xd8, 0xdf, 0xf2, 0x5b, 0x8a, 0x04, 0x19, 0x62, 0xdc, 0x60, 0x32, 0x90, 0xf5, + 0x82, 0x26, 0xb4, 0x01, 0x8d, 0x31, 0xe1, 0x36, 0xf1, 0x62, 0xc2, 0x4a, 0x1c, 0x88, 0x24, 0xfe, + 0x89, 0x76, 0x3a, 0x5f, 0x96, 0xba, 0x3b, 0xd3, 0x49, 0xdb, 0x59, 0xc2, 0xcd, 0x97, 0xe0, 0x3b, + 0xf0, 0xed, 0x70, 0xc4, 0x1b, 0x27, 0x22, 0x63, 0x7c, 0x1f, 0x66, 0x3a, 0x9d, 0xfd, 0xc3, 0xa2, + 0xc2, 0x6d, 0xa7, 0x7d, 0x9e, 0x4f, 0x9f, 0x7e, 0x9f, 0x66, 0xd1, 0x41, 0xef, 0xb9, 0xc2, 0x5c, + 0x90, 0x5e, 0x16, 0x82, 0x4c, 0x40, 0x83, 0x22, 0x03, 0x48, 0x22, 0x21, 0x89, 0xdd, 0x88, 0x41, + 0x4b, 0xce, 0x14, 0x49, 0x7b, 0x5d, 0x42, 0x53, 0xae, 0x08, 0xcb, 0x94, 0x16, 0xf1, 0xc7, 0x6a, + 0x7d, 0xb0, 0x19, 0x82, 0xa6, 0x9b, 0xa4, 0x0b, 0x09, 0x48, 0xaa, 0x21, 0xc2, 0xa9, 0x14, 0x5a, + 0xb8, 0xb8, 0xf4, 0x63, 0xab, 0xc3, 0x69, 0xaf, 0x8b, 0x0b, 0x3f, 0x9e, 0xf4, 0x63, 0xeb, 0x5f, + 0xd9, 0xe8, 0x72, 0x7d, 0x94, 0x85, 0x98, 0x89, 0x98, 0x74, 0x45, 0x57, 0x10, 0x83, 0x09, 0xb3, + 0x43, 0xf3, 0x65, 0x3e, 0xcc, 0xaf, 0x12, 0xbf, 0xd2, 0xb6, 0xf1, 0x68, 0xca, 0x09, 0x13, 0x12, + 0xc8, 0x60, 0x2a, 0xc2, 0xca, 0xd3, 0x91, 0x26, 0xa6, 0xec, 0x88, 0x27, 0x20, 0x4f, 0xaa, 0x7b, + 0x10, 0x09, 0x4a, 0x64, 0x92, 0xc1, 0xad, 0x5c, 0xaa, 0x18, 0x07, 0xbd, 0xee, 0x2c, 0xf2, 0x27, + 0x97, 0xcc, 0x12, 0xcd, 0xe3, 0xe9, 0x63, 0x9e, 0xfd, 0xcb, 0xa0, 0xd8, 0x11, 0xc4, 0xf4, 0xaa, + 0xaf, 0xfd, 0xcd, 0x41, 0x4b, 0x1d, 0x33, 0xbb, 0x1d, 0xae, 0xf4, 0x6e, 0xaa, 0xb9, 0x48, 0x94, + 0xbb, 0x8d, 0x16, 0xfa, 0x34, 0x84, 0xfe, 0x1e, 0xf4, 0x81, 0x69, 0x21, 0x5b, 0xce, 0x9a, 0xb3, + 0x3e, 0xe7, 0xdf, 0x3b, 0xbd, 0x58, 0xad, 0xe5, 0x17, 0xab, 0x0b, 0x3b, 0xe3, 0x9b, 0xc1, 0xa4, + 0xd6, 0xed, 0xa0, 0xe5, 0xb2, 0x8d, 0x09, 0x55, 0x6b, 0xc6, 0x20, 0x1e, 0x58, 0xc4, 0x72, 0x67, + 0x5a, 0x12, 0x5c, 0xe7, 0x6b, 0xff, 0xaa, 0xa3, 0xf9, 0x52, 0xfc, 0x86, 0xf6, 0x33, 0x70, 0x0f, + 0xd1, 0x62, 0x04, 0x8a, 0x49, 0x1e, 0x42, 0xb4, 0x1b, 0x7e, 0x06, 0xa6, 0x4d, 0xba, 0xf9, 0xad, + 0x87, 0xd5, 0x1b, 0xa1, 0x29, 0xc7, 0x45, 0x89, 0x78, 0xb0, 0x89, 0x4b, 0x45, 0x00, 0x87, 0x20, + 0x21, 0x61, 0xe0, 0xdf, 0xb7, 0xe7, 0x2f, 0xbe, 0x98, 0x64, 0x04, 0x57, 0xa1, 0xee, 0x16, 0x42, + 0x65, 0x9c, 0x57, 0x34, 0x06, 0x9b, 0xde, 0xb5, 0x6e, 0xd4, 0x19, 0xee, 0x04, 0x63, 0x2a, 0xf7, + 0x1d, 0x9a, 0x2b, 0x86, 0xad, 0x34, 0x8d, 0xd3, 0x56, 0xdd, 0xa4, 0x7a, 0x3c, 0x96, 0x6a, 0xd8, + 0xcc, 0xe8, 0xf9, 0x16, 0x0f, 0xa0, 0xc8, 0xb9, 0xcf, 0x63, 0xf0, 0x97, 0x2c, 0x7e, 0x6e, 0xbf, + 0x82, 0x04, 0x23, 0x9e, 0xfb, 0x08, 0xcd, 0x1e, 0xf3, 0x24, 0x12, 0xc7, 0xad, 0xff, 0xd6, 0x9c, + 0xf5, 0xba, 0xbf, 0x54, 0x34, 0x71, 0x60, 0x56, 0xf6, 0x80, 0x89, 0x24, 0x52, 0x81, 0x15, 0xb8, + 0x7b, 0xa8, 0x31, 0x28, 0x86, 0xd5, 0x6a, 0x98, 0x0c, 0xf8, 0x6f, 0x19, 0x70, 0xf5, 0x74, 0xf1, + 0xeb, 0x8c, 0x26, 0x9a, 0xeb, 0x13, 0x7f, 0xc1, 0xe6, 0x68, 0x98, 0x89, 0x07, 0x25, 0xcb, 0xfd, + 0x80, 0x9a, 0xaa, 0x2a, 0x73, 0xd6, 0x70, 0x9f, 0xdc, 0xec, 0x6e, 0x13, 0x7d, 0xfa, 0x77, 0xf2, + 0x8b, 0xd5, 0xe6, 0xb0, 0xf2, 0x21, 0xb2, 0xfd, 0xdd, 0x41, 0x8b, 0x63, 0x3d, 0x17, 0xcf, 0xd1, + 0x7d, 0x8f, 0x9a, 0x05, 0x24, 0xa2, 0x9a, 0xda, 0x92, 0xf1, 0x0d, 0x8f, 0xe4, 0x4a, 0x77, 0x40, + 0x53, 0xff, 0xae, 0xbd, 0x4a, 0xb3, 0x5a, 0x09, 0x86, 0x44, 0xf7, 0x13, 0x6a, 0x70, 0x0d, 0xb1, + 0x6a, 0xcd, 0xac, 0xd5, 0xd7, 0xe7, 0xb7, 0xb6, 0x6f, 0xf9, 0x1f, 0x83, 0xc7, 0xd2, 0x8e, 0x46, + 0xf6, 0xb2, 0x20, 0x06, 0x25, 0xd8, 0xdf, 0x38, 0xbd, 0xf4, 0x6a, 0x67, 0x97, 0x5e, 0xed, 0xfc, + 0xd2, 0xab, 0x7d, 0xc9, 0x3d, 0xe7, 0x34, 0xf7, 0x9c, 0xb3, 0xdc, 0x73, 0xce, 0x73, 0xcf, 0xf9, + 0x91, 0x7b, 0xce, 0xd7, 0x9f, 0x5e, 0xed, 0xed, 0xff, 0x16, 0xf8, 0x3b, 0x00, 0x00, 0xff, 0xff, + 0xf5, 0x23, 0xb5, 0xdc, 0x3e, 0x05, 0x00, 0x00, } diff --git a/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1/generated.proto b/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1/generated.proto index 76b8995056..9d4d259679 100644 --- a/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1/generated.proto +++ b/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1/generated.proto @@ -30,6 +30,18 @@ import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; // Package-wide variables from generator "generated". option go_package = "v1beta1"; +// MetricListOptions is used to select metrics by their label selectors +message MetricListOptions { + // A selector to restrict the list of returned objects by their labels. + // Defaults to everything. + // +optional + optional string labelSelector = 1; + + // A selector to restrict the list of returned metrics by their labels + // +optional + optional string metricLabelSelector = 2; +} + // a metric value for some object message MetricValue { // a reference to the described object diff --git a/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1/register.go b/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1/register.go index 42fd2b92f0..f1b43e9cb6 100644 --- a/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1/register.go +++ b/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1/register.go @@ -43,6 +43,7 @@ func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &MetricValue{}, &MetricValueList{}, + &MetricListOptions{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil diff --git a/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1/types.go b/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1/types.go index 8f5901896a..aa97053ca6 100644 --- a/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1/types.go +++ b/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1/types.go @@ -65,6 +65,22 @@ type MetricValue struct { Selector *metav1.LabelSelector `json:"selector" protobuf:"bytes,6,opt,name=selector"` } +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// MetricListOptions is used to select metrics by their label selectors +type MetricListOptions struct { + metav1.TypeMeta `json:",inline"` + + // A selector to restrict the list of returned objects by their labels. + // Defaults to everything. + // +optional + LabelSelector string `json:"labelSelector,omitempty" protobuf:"bytes,1,opt,name=labelSelector"` + + // A selector to restrict the list of returned metrics by their labels + // +optional + MetricLabelSelector string `json:"metricLabelSelector,omitempty" protobuf:"bytes,2,opt,name=metricLabelSelector"` +} + // allObjects is a wildcard used to select metrics // for all objects matching the given label selector const AllObjects = "*" diff --git a/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1/zz_generated.conversion.go b/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1/zz_generated.conversion.go index 5122f74d9d..d3c587b8b6 100644 --- a/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1/zz_generated.conversion.go +++ b/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1/zz_generated.conversion.go @@ -35,6 +35,16 @@ func init() { // RegisterConversions adds conversion functions to the given scheme. // Public to allow building arbitrary schemes. func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*MetricListOptions)(nil), (*custommetrics.MetricListOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_MetricListOptions_To_custom_metrics_MetricListOptions(a.(*MetricListOptions), b.(*custommetrics.MetricListOptions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*custommetrics.MetricListOptions)(nil), (*MetricListOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_custom_metrics_MetricListOptions_To_v1beta1_MetricListOptions(a.(*custommetrics.MetricListOptions), b.(*MetricListOptions), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*MetricValue)(nil), (*custommetrics.MetricValue)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta1_MetricValue_To_custom_metrics_MetricValue(a.(*MetricValue), b.(*custommetrics.MetricValue), scope) }); err != nil { @@ -68,6 +78,28 @@ func RegisterConversions(s *runtime.Scheme) error { return nil } +func autoConvert_v1beta1_MetricListOptions_To_custom_metrics_MetricListOptions(in *MetricListOptions, out *custommetrics.MetricListOptions, s conversion.Scope) error { + out.LabelSelector = in.LabelSelector + out.MetricLabelSelector = in.MetricLabelSelector + return nil +} + +// Convert_v1beta1_MetricListOptions_To_custom_metrics_MetricListOptions is an autogenerated conversion function. +func Convert_v1beta1_MetricListOptions_To_custom_metrics_MetricListOptions(in *MetricListOptions, out *custommetrics.MetricListOptions, s conversion.Scope) error { + return autoConvert_v1beta1_MetricListOptions_To_custom_metrics_MetricListOptions(in, out, s) +} + +func autoConvert_custom_metrics_MetricListOptions_To_v1beta1_MetricListOptions(in *custommetrics.MetricListOptions, out *MetricListOptions, s conversion.Scope) error { + out.LabelSelector = in.LabelSelector + out.MetricLabelSelector = in.MetricLabelSelector + return nil +} + +// Convert_custom_metrics_MetricListOptions_To_v1beta1_MetricListOptions is an autogenerated conversion function. +func Convert_custom_metrics_MetricListOptions_To_v1beta1_MetricListOptions(in *custommetrics.MetricListOptions, out *MetricListOptions, s conversion.Scope) error { + return autoConvert_custom_metrics_MetricListOptions_To_v1beta1_MetricListOptions(in, out, s) +} + func autoConvert_v1beta1_MetricValue_To_custom_metrics_MetricValue(in *MetricValue, out *custommetrics.MetricValue, s conversion.Scope) error { // TODO: Inefficient conversion - can we improve it? if err := s.Convert(&in.DescribedObject, &out.DescribedObject, 0); err != nil { diff --git a/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1/zz_generated.deepcopy.go b/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1/zz_generated.deepcopy.go index c3e6a2614a..4d2e11c725 100644 --- a/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1/zz_generated.deepcopy.go +++ b/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1/zz_generated.deepcopy.go @@ -25,6 +25,31 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MetricListOptions) DeepCopyInto(out *MetricListOptions) { + *out = *in + out.TypeMeta = in.TypeMeta + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricListOptions. +func (in *MetricListOptions) DeepCopy() *MetricListOptions { + if in == nil { + return nil + } + out := new(MetricListOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MetricListOptions) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MetricValue) DeepCopyInto(out *MetricValue) { *out = *in diff --git a/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta2/zz_generated.conversion.go b/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta2/zz_generated.conversion.go index bb38f4cb31..6a12d03444 100644 --- a/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta2/zz_generated.conversion.go +++ b/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta2/zz_generated.conversion.go @@ -46,6 +46,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*MetricListOptions)(nil), (*custommetrics.MetricListOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta2_MetricListOptions_To_custom_metrics_MetricListOptions(a.(*MetricListOptions), b.(*custommetrics.MetricListOptions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*custommetrics.MetricListOptions)(nil), (*MetricListOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_custom_metrics_MetricListOptions_To_v1beta2_MetricListOptions(a.(*custommetrics.MetricListOptions), b.(*MetricListOptions), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*MetricValue)(nil), (*custommetrics.MetricValue)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta2_MetricValue_To_custom_metrics_MetricValue(a.(*MetricValue), b.(*custommetrics.MetricValue), scope) }); err != nil { @@ -91,6 +101,28 @@ func Convert_custom_metrics_MetricIdentifier_To_v1beta2_MetricIdentifier(in *cus return autoConvert_custom_metrics_MetricIdentifier_To_v1beta2_MetricIdentifier(in, out, s) } +func autoConvert_v1beta2_MetricListOptions_To_custom_metrics_MetricListOptions(in *MetricListOptions, out *custommetrics.MetricListOptions, s conversion.Scope) error { + out.LabelSelector = in.LabelSelector + out.MetricLabelSelector = in.MetricLabelSelector + return nil +} + +// Convert_v1beta2_MetricListOptions_To_custom_metrics_MetricListOptions is an autogenerated conversion function. +func Convert_v1beta2_MetricListOptions_To_custom_metrics_MetricListOptions(in *MetricListOptions, out *custommetrics.MetricListOptions, s conversion.Scope) error { + return autoConvert_v1beta2_MetricListOptions_To_custom_metrics_MetricListOptions(in, out, s) +} + +func autoConvert_custom_metrics_MetricListOptions_To_v1beta2_MetricListOptions(in *custommetrics.MetricListOptions, out *MetricListOptions, s conversion.Scope) error { + out.LabelSelector = in.LabelSelector + out.MetricLabelSelector = in.MetricLabelSelector + return nil +} + +// Convert_custom_metrics_MetricListOptions_To_v1beta2_MetricListOptions is an autogenerated conversion function. +func Convert_custom_metrics_MetricListOptions_To_v1beta2_MetricListOptions(in *custommetrics.MetricListOptions, out *MetricListOptions, s conversion.Scope) error { + return autoConvert_custom_metrics_MetricListOptions_To_v1beta2_MetricListOptions(in, out, s) +} + func autoConvert_v1beta2_MetricValue_To_custom_metrics_MetricValue(in *MetricValue, out *custommetrics.MetricValue, s conversion.Scope) error { // TODO: Inefficient conversion - can we improve it? if err := s.Convert(&in.DescribedObject, &out.DescribedObject, 0); err != nil { diff --git a/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/zz_generated.deepcopy.go b/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/zz_generated.deepcopy.go index 0c110bbf51..a80a69130f 100644 --- a/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/zz_generated.deepcopy.go +++ b/staging/src/k8s.io/metrics/pkg/apis/custom_metrics/zz_generated.deepcopy.go @@ -46,6 +46,31 @@ func (in *MetricIdentifier) DeepCopy() *MetricIdentifier { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MetricListOptions) DeepCopyInto(out *MetricListOptions) { + *out = *in + out.TypeMeta = in.TypeMeta + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricListOptions. +func (in *MetricListOptions) DeepCopy() *MetricListOptions { + if in == nil { + return nil + } + out := new(MetricListOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MetricListOptions) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MetricValue) DeepCopyInto(out *MetricValue) { *out = *in diff --git a/staging/src/k8s.io/metrics/pkg/client/custom_metrics/BUILD b/staging/src/k8s.io/metrics/pkg/client/custom_metrics/BUILD index 262d485c93..90c00c9919 100644 --- a/staging/src/k8s.io/metrics/pkg/client/custom_metrics/BUILD +++ b/staging/src/k8s.io/metrics/pkg/client/custom_metrics/BUILD @@ -1,21 +1,29 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "go_default_library", srcs = [ - "client.go", + "converter.go", + "discovery.go", "interfaces.go", + "multi_client.go", + "versioned_client.go", ], importmap = "k8s.io/kubernetes/vendor/k8s.io/metrics/pkg/client/custom_metrics", importpath = "k8s.io/metrics/pkg/client/custom_metrics", visibility = ["//visibility:public"], deps = [ "//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library", + "//staging/src/k8s.io/client-go/discovery:go_default_library", "//staging/src/k8s.io/client-go/rest:go_default_library", "//staging/src/k8s.io/client-go/util/flowcontrol:go_default_library", + "//staging/src/k8s.io/metrics/pkg/apis/custom_metrics:go_default_library", + "//staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1:go_default_library", "//staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta2:go_default_library", "//staging/src/k8s.io/metrics/pkg/client/custom_metrics/scheme:go_default_library", ], @@ -38,3 +46,18 @@ filegroup( tags = ["automanaged"], visibility = ["//visibility:public"], ) + +go_test( + name = "go_default_test", + srcs = ["util_test.go"], + embed = [":go_default_library"], + deps = [ + "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", + "//staging/src/k8s.io/metrics/pkg/apis/custom_metrics:go_default_library", + "//staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1:go_default_library", + "//staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta2:go_default_library", + "//vendor/github.com/stretchr/testify/require:go_default_library", + ], +) diff --git a/staging/src/k8s.io/metrics/pkg/client/custom_metrics/converter.go b/staging/src/k8s.io/metrics/pkg/client/custom_metrics/converter.go new file mode 100644 index 0000000000..d83d467020 --- /dev/null +++ b/staging/src/k8s.io/metrics/pkg/client/custom_metrics/converter.go @@ -0,0 +1,122 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 custom_metrics + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/client-go/rest" + + cmint "k8s.io/metrics/pkg/apis/custom_metrics" + cmv1beta1 "k8s.io/metrics/pkg/apis/custom_metrics/v1beta1" + cmv1beta2 "k8s.io/metrics/pkg/apis/custom_metrics/v1beta2" + "k8s.io/metrics/pkg/client/custom_metrics/scheme" +) + +var ( + // MetricVersions is the set of metric versions accepted by the converter. + MetricVersions = []schema.GroupVersion{ + cmv1beta2.SchemeGroupVersion, + cmv1beta1.SchemeGroupVersion, + cmint.SchemeGroupVersion, + } +) + +// MetricConverter knows how to convert between external MetricValue versions. +type MetricConverter struct { + scheme *runtime.Scheme + codecs serializer.CodecFactory + internalVersioner runtime.GroupVersioner +} + +// NewMetricConverter creates a MetricConverter which knows how to convert objects +// between different versions of the custom metrics api. +func NewMetricConverter() *MetricConverter { + return &MetricConverter{ + scheme: scheme.Scheme, + codecs: serializer.NewCodecFactory(scheme.Scheme), + internalVersioner: runtime.NewMultiGroupVersioner( + scheme.SchemeGroupVersion, + schema.GroupKind{Group: cmint.GroupName, Kind: ""}, + schema.GroupKind{Group: cmv1beta1.GroupName, Kind: ""}, + schema.GroupKind{Group: cmv1beta2.GroupName, Kind: ""}, + ), + } +} + +// Scheme returns the scheme used by this metric converter. +func (c *MetricConverter) Scheme() *runtime.Scheme { + return c.scheme +} + +// Codecs returns the codecs used by this metric converter +func (c *MetricConverter) Codecs() serializer.CodecFactory { + return c.codecs +} + +// ConvertListOptionsToVersion converts converts a set of MetricListOptions +// to the provided GroupVersion. +func (c *MetricConverter) ConvertListOptionsToVersion(opts *cmint.MetricListOptions, version schema.GroupVersion) (runtime.Object, error) { + paramObj, err := c.UnsafeConvertToVersionVia(opts, version) + if err != nil { + return nil, err + } + return paramObj, nil +} + +// ConvertResultToVersion converts a Result to the provided GroupVersion +func (c *MetricConverter) ConvertResultToVersion(res rest.Result, gv schema.GroupVersion) (runtime.Object, error) { + if err := res.Error(); err != nil { + return nil, err + } + + metricBytes, err := res.Raw() + if err != nil { + return nil, err + } + + decoder := c.codecs.UniversalDecoder(MetricVersions...) + rawMetricObj, err := runtime.Decode(decoder, metricBytes) + if err != nil { + return nil, err + } + + metricObj, err := c.UnsafeConvertToVersionVia(rawMetricObj, gv) + if err != nil { + return nil, err + } + return metricObj, nil +} + +// unsafeConvertToVersionVia is like Scheme.UnsafeConvertToVersion, but it does so via an internal version first. +// We use it here to work with the v1beta2 client internally, while preserving backwards compatibility for existing custom metrics adapters +func (c *MetricConverter) UnsafeConvertToVersionVia(obj runtime.Object, externalVersion schema.GroupVersion) (runtime.Object, error) { + objInt, err := c.scheme.UnsafeConvertToVersion(obj, schema.GroupVersion{Group: externalVersion.Group, Version: runtime.APIVersionInternal}) + if err != nil { + return nil, fmt.Errorf("failed to convert the given object to the internal version: %v", err) + } + + objExt, err := c.scheme.UnsafeConvertToVersion(objInt, externalVersion) + if err != nil { + return nil, fmt.Errorf("failed to convert the given object back to the external version: %v", err) + } + + return objExt, err +} diff --git a/staging/src/k8s.io/metrics/pkg/client/custom_metrics/discovery.go b/staging/src/k8s.io/metrics/pkg/client/custom_metrics/discovery.go new file mode 100644 index 0000000000..7c9f8951bb --- /dev/null +++ b/staging/src/k8s.io/metrics/pkg/client/custom_metrics/discovery.go @@ -0,0 +1,145 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 custom_metrics + +import ( + "fmt" + "sync" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/discovery" + + cmint "k8s.io/metrics/pkg/apis/custom_metrics" +) + +var ( + // metricVersionsToGV is the map of string group-versions + // accepted by the converter to group-version objects (so + // we don't have to re-parse) + metricVersionsToGV map[string]schema.GroupVersion +) + +func init() { + metricVersionsToGV = make(map[string]schema.GroupVersion) + for _, ver := range MetricVersions { + metricVersionsToGV[ver.String()] = ver + } +} + +// NewAvailableAPIsGetter creates an AvailableAPIsGetter that checks discovery +// to find the available versions of the custom metrics api. +func NewAvailableAPIsGetter(client discovery.DiscoveryInterface) AvailableAPIsGetter { + return &apiVersionsFromDiscovery{ + client: client, + } +} + +// apiVersionsFromDiscovery caches a preferred version of the custom metrics api. +type apiVersionsFromDiscovery struct { + client discovery.DiscoveryInterface + + // just cache the group directly since the discovery interface doesn't yet allow + // asking for a single API group's versions. + prefVersion *schema.GroupVersion + mu sync.RWMutex +} + +// fetchVersions fetches the versions, but doesn't try to invalidate on cache misses. +func (d *apiVersionsFromDiscovery) fetchVersions() (*metav1.APIGroup, error) { + // TODO(directxman12): amend the discovery interface to ask for a particular group (/apis/foo) + groups, err := d.client.ServerGroups() + if err != nil { + return nil, err + } + + // Determine the preferred version on the server by first finding the custom metrics group + var apiGroup *metav1.APIGroup + for _, group := range groups.Groups { + if group.Name == cmint.GroupName { + apiGroup = &group + break + } + } + + if apiGroup == nil { + return nil, fmt.Errorf("no custom metrics API (%s) registered", cmint.GroupName) + } + + return apiGroup, nil +} + +// chooseVersion sets a preferred version of the custom metrics api based on available versions. +func (d *apiVersionsFromDiscovery) chooseVersion(apiGroup *metav1.APIGroup) (schema.GroupVersion, error) { + var preferredVersion *schema.GroupVersion + if gv, present := metricVersionsToGV[apiGroup.PreferredVersion.GroupVersion]; present && len(apiGroup.PreferredVersion.GroupVersion) != 0 { + preferredVersion = &gv + } else { + for _, version := range apiGroup.Versions { + if gv, present := metricVersionsToGV[version.GroupVersion]; present { + preferredVersion = &gv + break + } + } + } + + if preferredVersion == nil { + return schema.GroupVersion{}, fmt.Errorf("no known available metric versions found") + } + return *preferredVersion, nil +} + +// PreferredVersion returns the current preferred version of the custom metrics api. +// If none is specified, it will use the first known one. +func (d *apiVersionsFromDiscovery) PreferredVersion() (schema.GroupVersion, error) { + d.mu.RLock() + if d.prefVersion != nil { + // if we've already got one, proceed with that + defer d.mu.RUnlock() + return *d.prefVersion, nil + } + d.mu.RUnlock() + + d.mu.Lock() + defer d.mu.Unlock() + + // double check, someone might have beaten us to it + if d.prefVersion != nil { + return *d.prefVersion, nil + } + + // populate our cache + groupInfo, err := d.fetchVersions() + if err != nil { + return schema.GroupVersion{}, err + } + prefVersion, err := d.chooseVersion(groupInfo) + if err != nil { + return schema.GroupVersion{}, err + } + + d.prefVersion = &prefVersion + return *d.prefVersion, nil +} + +// Invalidate refreshes the preferred version information. +func (d *apiVersionsFromDiscovery) Invalidate() { + d.mu.Lock() + defer d.mu.Unlock() + + d.prefVersion = nil +} diff --git a/staging/src/k8s.io/metrics/pkg/client/custom_metrics/multi_client.go b/staging/src/k8s.io/metrics/pkg/client/custom_metrics/multi_client.go new file mode 100644 index 0000000000..cbc91a9d26 --- /dev/null +++ b/staging/src/k8s.io/metrics/pkg/client/custom_metrics/multi_client.go @@ -0,0 +1,138 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 custom_metrics + +import ( + "sync" + "time" + + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/rest" + + "k8s.io/metrics/pkg/apis/custom_metrics/v1beta2" +) + +// AvailableAPIsGetter knows how to fetch and cache the preferred custom metrics API version, +// and invalidate that cache when asked. +type AvailableAPIsGetter interface { + PreferredVersion() (schema.GroupVersion, error) + Invalidate() +} + +// PeriodicallyInvalidate periodically invalidates the preferred version cache until +// told to stop. +func PeriodicallyInvalidate(cache AvailableAPIsGetter, interval time.Duration, stopCh <-chan struct{}) { + ticker := time.NewTicker(interval) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + cache.Invalidate() + case <-stopCh: + break + } + } +} + +// NewForConfig creates a new custom metrics client which delegates to a client which +// uses the preferred api version. +func NewForConfig(baseConfig *rest.Config, mapper meta.RESTMapper, availableAPIs AvailableAPIsGetter) CustomMetricsClient { + return &multiClient{ + clients: make(map[schema.GroupVersion]CustomMetricsClient), + availableAPIs: availableAPIs, + + newClient: func(ver schema.GroupVersion) (CustomMetricsClient, error) { + return NewForVersionForConfig(rest.CopyConfig(baseConfig), mapper, ver) + }, + } +} + +// multiClient is a CustomMetricsClient that can work with *any* metrics API version. +type multiClient struct { + newClient func(schema.GroupVersion) (CustomMetricsClient, error) + clients map[schema.GroupVersion]CustomMetricsClient + availableAPIs AvailableAPIsGetter + mu sync.RWMutex +} + +// getPreferredClient returns a custom metrics client of the preferred api version. +func (c *multiClient) getPreferredClient() (CustomMetricsClient, error) { + pref, err := c.availableAPIs.PreferredVersion() + if err != nil { + return nil, err + } + + c.mu.RLock() + client, present := c.clients[pref] + c.mu.RUnlock() + if present { + return client, nil + } + + c.mu.Lock() + defer c.mu.Unlock() + client, err = c.newClient(pref) + if err != nil { + return nil, err + } + c.clients[pref] = client + + return client, nil +} + +func (c *multiClient) RootScopedMetrics() MetricsInterface { + return &multiClientInterface{clients: c} +} + +func (c *multiClient) NamespacedMetrics(namespace string) MetricsInterface { + return &multiClientInterface{ + clients: c, + namespace: &namespace, + } +} + +type multiClientInterface struct { + clients *multiClient + namespace *string +} + +func (m *multiClientInterface) GetForObject(groupKind schema.GroupKind, name string, metricName string, metricSelector labels.Selector) (*v1beta2.MetricValue, error) { + client, err := m.clients.getPreferredClient() + if err != nil { + return nil, err + } + if m.namespace == nil { + return client.RootScopedMetrics().GetForObject(groupKind, name, metricName, metricSelector) + } else { + return client.NamespacedMetrics(*m.namespace).GetForObject(groupKind, name, metricName, metricSelector) + } +} + +func (m *multiClientInterface) GetForObjects(groupKind schema.GroupKind, selector labels.Selector, metricName string, metricSelector labels.Selector) (*v1beta2.MetricValueList, error) { + client, err := m.clients.getPreferredClient() + if err != nil { + return nil, err + } + if m.namespace == nil { + return client.RootScopedMetrics().GetForObjects(groupKind, selector, metricName, metricSelector) + } else { + return client.NamespacedMetrics(*m.namespace).GetForObjects(groupKind, selector, metricName, metricSelector) + } +} diff --git a/staging/src/k8s.io/metrics/pkg/client/custom_metrics/scheme/BUILD b/staging/src/k8s.io/metrics/pkg/client/custom_metrics/scheme/BUILD index 42e136a6ed..85e6e80a57 100644 --- a/staging/src/k8s.io/metrics/pkg/client/custom_metrics/scheme/BUILD +++ b/staging/src/k8s.io/metrics/pkg/client/custom_metrics/scheme/BUILD @@ -11,6 +11,7 @@ go_library( "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library", + "//staging/src/k8s.io/metrics/pkg/apis/custom_metrics:go_default_library", "//staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1:go_default_library", "//staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta2:go_default_library", ], diff --git a/staging/src/k8s.io/metrics/pkg/client/custom_metrics/scheme/register.go b/staging/src/k8s.io/metrics/pkg/client/custom_metrics/scheme/register.go index 314415517a..9875f42f9c 100644 --- a/staging/src/k8s.io/metrics/pkg/client/custom_metrics/scheme/register.go +++ b/staging/src/k8s.io/metrics/pkg/client/custom_metrics/scheme/register.go @@ -21,10 +21,15 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" serializer "k8s.io/apimachinery/pkg/runtime/serializer" + cmint "k8s.io/metrics/pkg/apis/custom_metrics" cmv1beta1 "k8s.io/metrics/pkg/apis/custom_metrics/v1beta1" cmv1beta2 "k8s.io/metrics/pkg/apis/custom_metrics/v1beta2" ) +const GroupName = cmv1beta1.GroupName + +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal} + var Scheme = runtime.NewScheme() var Codecs = serializer.NewCodecFactory(Scheme) var ParameterCodec = runtime.NewParameterCodec(Scheme) @@ -49,6 +54,7 @@ func init() { // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types // correctly. func AddToScheme(scheme *runtime.Scheme) { + cmint.AddToScheme(scheme) cmv1beta1.AddToScheme(scheme) cmv1beta2.AddToScheme(scheme) } diff --git a/staging/src/k8s.io/metrics/pkg/client/custom_metrics/util_test.go b/staging/src/k8s.io/metrics/pkg/client/custom_metrics/util_test.go new file mode 100644 index 0000000000..5d5dd12ef9 --- /dev/null +++ b/staging/src/k8s.io/metrics/pkg/client/custom_metrics/util_test.go @@ -0,0 +1,65 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 custom_metrics + +import ( + "testing" + + "github.com/stretchr/testify/require" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + + cmint "k8s.io/metrics/pkg/apis/custom_metrics" + cmv1beta1 "k8s.io/metrics/pkg/apis/custom_metrics/v1beta1" + cmv1beta2 "k8s.io/metrics/pkg/apis/custom_metrics/v1beta2" +) + +func TestMetricConverter(t *testing.T) { + testCases := []struct { + name string + group schema.GroupVersion + expected runtime.Object + }{ + { + name: "Use custom metrics v1beta2", + group: cmv1beta2.SchemeGroupVersion, + expected: &cmv1beta2.MetricListOptions{ + TypeMeta: metav1.TypeMeta{Kind: "MetricListOptions", APIVersion: cmv1beta2.SchemeGroupVersion.String()}, + MetricLabelSelector: "foo", + }, + }, + { + name: "Use custom metrics v1beta1", + group: cmv1beta1.SchemeGroupVersion, + expected: &cmv1beta1.MetricListOptions{ + TypeMeta: metav1.TypeMeta{Kind: "MetricListOptions", APIVersion: cmv1beta1.SchemeGroupVersion.String()}, + MetricLabelSelector: "foo", + }, + }, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + metricConverter := NewMetricConverter() + opts := &cmint.MetricListOptions{MetricLabelSelector: "foo"} + res, err := metricConverter.ConvertListOptionsToVersion(opts, test.group) + require.NoError(t, err) + require.Equal(t, test.expected, res) + }) + } +} diff --git a/staging/src/k8s.io/metrics/pkg/client/custom_metrics/client.go b/staging/src/k8s.io/metrics/pkg/client/custom_metrics/versioned_client.go similarity index 61% rename from staging/src/k8s.io/metrics/pkg/client/custom_metrics/client.go rename to staging/src/k8s.io/metrics/pkg/client/custom_metrics/versioned_client.go index d399ca059c..f26785bf8e 100644 --- a/staging/src/k8s.io/metrics/pkg/client/custom_metrics/client.go +++ b/staging/src/k8s.io/metrics/pkg/client/custom_metrics/versioned_client.go @@ -25,22 +25,35 @@ import ( serializer "k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/client-go/rest" "k8s.io/client-go/util/flowcontrol" + + cmint "k8s.io/metrics/pkg/apis/custom_metrics" + "k8s.io/metrics/pkg/apis/custom_metrics/v1beta1" "k8s.io/metrics/pkg/apis/custom_metrics/v1beta2" "k8s.io/metrics/pkg/client/custom_metrics/scheme" ) +var ( + codecs = serializer.NewCodecFactory(scheme.Scheme) + versionConverter = NewMetricConverter() +) + type customMetricsClient struct { - client rest.Interface - mapper meta.RESTMapper + client rest.Interface + version schema.GroupVersion + mapper meta.RESTMapper } -func New(client rest.Interface) CustomMetricsClient { +// NewForVersion returns a new CustomMetricsClient for a particular api version. +func NewForVersion(client rest.Interface, mapper meta.RESTMapper, version schema.GroupVersion) CustomMetricsClient { return &customMetricsClient{ - client: client, + client: client, + version: version, + mapper: mapper, } } -func NewForConfig(c *rest.Config) (CustomMetricsClient, error) { +// NewForVersionForConfig returns a new CustomMetricsClient for a particular api version and base configuration. +func NewForVersionForConfig(c *rest.Config, mapper meta.RESTMapper, version schema.GroupVersion) (CustomMetricsClient, error) { configShallowCopy := *c if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) @@ -49,7 +62,7 @@ func NewForConfig(c *rest.Config) (CustomMetricsClient, error) { if configShallowCopy.UserAgent == "" { configShallowCopy.UserAgent = rest.DefaultKubernetesUserAgent() } - configShallowCopy.GroupVersion = &v1beta2.SchemeGroupVersion + configShallowCopy.GroupVersion = &version configShallowCopy.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} client, err := rest.RESTClientFor(&configShallowCopy) @@ -57,24 +70,7 @@ func NewForConfig(c *rest.Config) (CustomMetricsClient, error) { return nil, err } - return New(client), nil -} - -func NewForConfigOrDie(c *rest.Config) CustomMetricsClient { - client, err := NewForConfig(c) - if err != nil { - panic(err) - } - return client -} - -// NewForMapper constructs the client with a RESTMapper, which allows more -// accurate translation from GroupVersionKind to GroupVersionResource. -func NewForMapper(client rest.Interface, mapper meta.RESTMapper) CustomMetricsClient { - return &customMetricsClient{ - client: client, - mapper: mapper, - } + return NewForVersion(client, mapper, version), nil } func (c *customMetricsClient) RootScopedMetrics() MetricsInterface { @@ -88,16 +84,8 @@ func (c *customMetricsClient) NamespacedMetrics(namespace string) MetricsInterfa } } +// qualResourceForKind returns the string format of a qualified group resource for the specified GroupKind func (c *customMetricsClient) qualResourceForKind(groupKind schema.GroupKind) (string, error) { - if c.mapper == nil { - // the version doesn't matter - gvk := groupKind.WithVersion("") - gvr, _ := meta.UnsafeGuessKindToResource(gvk) - gr := gvr.GroupResource() - return gr.String(), nil - } - - // use the mapper if it's available mapping, err := c.mapper.RESTMapping(groupKind) if err != nil { return "", fmt.Errorf("unable to map kind %s to resource: %v", groupKind.String(), err) @@ -112,21 +100,26 @@ type rootScopedMetrics struct { } func (m *rootScopedMetrics) getForNamespace(namespace string, metricName string, metricSelector labels.Selector) (*v1beta2.MetricValue, error) { - res := &v1beta2.MetricValueList{} - err := m.client.client.Get(). - Resource("metrics"). - Namespace(namespace). - Name(metricName). - VersionedParams(&v1beta2.MetricListOptions{ - MetricLabelSelector: metricSelector.String(), - }, scheme.ParameterCodec). - Do(). - Into(res) - + params, err := versionConverter.ConvertListOptionsToVersion(&cmint.MetricListOptions{ + MetricLabelSelector: metricSelector.String(), + }, m.client.version) if err != nil { return nil, err } + result := m.client.client.Get(). + Resource("metrics"). + Namespace(namespace). + Name(metricName). + VersionedParams(params, scheme.ParameterCodec). + Do() + + metricObj, err := versionConverter.ConvertResultToVersion(result, v1beta2.SchemeGroupVersion) + if err != nil { + return nil, err + } + + res := metricObj.(*v1beta2.MetricValueList) if len(res.Items) != 1 { return nil, fmt.Errorf("the custom metrics API server returned %v results when we asked for exactly one", len(res.Items)) } @@ -145,21 +138,26 @@ func (m *rootScopedMetrics) GetForObject(groupKind schema.GroupKind, name string return nil, err } - res := &v1beta2.MetricValueList{} - err = m.client.client.Get(). - Resource(resourceName). - Name(name). - SubResource(metricName). - VersionedParams(&v1beta2.MetricListOptions{ - MetricLabelSelector: metricSelector.String(), - }, scheme.ParameterCodec). - Do(). - Into(res) - + params, err := versionConverter.ConvertListOptionsToVersion(&cmint.MetricListOptions{ + MetricLabelSelector: metricSelector.String(), + }, m.client.version) if err != nil { return nil, err } + result := m.client.client.Get(). + Resource(resourceName). + Name(name). + SubResource(metricName). + VersionedParams(params, scheme.ParameterCodec). + Do() + + metricObj, err := versionConverter.ConvertResultToVersion(result, v1beta2.SchemeGroupVersion) + if err != nil { + return nil, err + } + + res := metricObj.(*v1beta2.MetricValueList) if len(res.Items) != 1 { return nil, fmt.Errorf("the custom metrics API server returned %v results when we asked for exactly one", len(res.Items)) } @@ -178,22 +176,27 @@ func (m *rootScopedMetrics) GetForObjects(groupKind schema.GroupKind, selector l return nil, err } - res := &v1beta2.MetricValueList{} - err = m.client.client.Get(). - Resource(resourceName). - Name(v1beta2.AllObjects). - SubResource(metricName). - VersionedParams(&v1beta2.MetricListOptions{ - LabelSelector: selector.String(), - MetricLabelSelector: metricSelector.String(), - }, scheme.ParameterCodec). - Do(). - Into(res) - + params, err := versionConverter.ConvertListOptionsToVersion(&cmint.MetricListOptions{ + LabelSelector: selector.String(), + MetricLabelSelector: metricSelector.String(), + }, m.client.version) if err != nil { return nil, err } + result := m.client.client.Get(). + Resource(resourceName). + Name(v1beta1.AllObjects). + SubResource(metricName). + VersionedParams(params, scheme.ParameterCodec). + Do() + + metricObj, err := versionConverter.ConvertResultToVersion(result, v1beta2.SchemeGroupVersion) + if err != nil { + return nil, err + } + + res := metricObj.(*v1beta2.MetricValueList) return res, nil } @@ -208,22 +211,27 @@ func (m *namespacedMetrics) GetForObject(groupKind schema.GroupKind, name string return nil, err } - res := &v1beta2.MetricValueList{} - err = m.client.client.Get(). - Resource(resourceName). - Namespace(m.namespace). - Name(name). - SubResource(metricName). - VersionedParams(&v1beta2.MetricListOptions{ - MetricLabelSelector: metricSelector.String(), - }, scheme.ParameterCodec). - Do(). - Into(res) - + params, err := versionConverter.ConvertListOptionsToVersion(&cmint.MetricListOptions{ + MetricLabelSelector: metricSelector.String(), + }, m.client.version) if err != nil { return nil, err } + result := m.client.client.Get(). + Resource(resourceName). + Namespace(m.namespace). + Name(name). + SubResource(metricName). + VersionedParams(params, scheme.ParameterCodec). + Do() + + metricObj, err := versionConverter.ConvertResultToVersion(result, v1beta2.SchemeGroupVersion) + if err != nil { + return nil, err + } + + res := metricObj.(*v1beta2.MetricValueList) if len(res.Items) != 1 { return nil, fmt.Errorf("the custom metrics API server returned %v results when we asked for exactly one", len(res.Items)) } @@ -237,22 +245,27 @@ func (m *namespacedMetrics) GetForObjects(groupKind schema.GroupKind, selector l return nil, err } - res := &v1beta2.MetricValueList{} - err = m.client.client.Get(). - Resource(resourceName). - Namespace(m.namespace). - Name(v1beta2.AllObjects). - SubResource(metricName). - VersionedParams(&v1beta2.MetricListOptions{ - LabelSelector: selector.String(), - MetricLabelSelector: metricSelector.String(), - }, scheme.ParameterCodec). - Do(). - Into(res) - + params, err := versionConverter.ConvertListOptionsToVersion(&cmint.MetricListOptions{ + LabelSelector: selector.String(), + MetricLabelSelector: metricSelector.String(), + }, m.client.version) if err != nil { return nil, err } + result := m.client.client.Get(). + Resource(resourceName). + Namespace(m.namespace). + Name(v1beta1.AllObjects). + SubResource(metricName). + VersionedParams(params, scheme.ParameterCodec). + Do() + + metricObj, err := versionConverter.ConvertResultToVersion(result, v1beta2.SchemeGroupVersion) + if err != nil { + return nil, err + } + + res := metricObj.(*v1beta2.MetricValueList) return res, nil } diff --git a/test/e2e/instrumentation/monitoring/BUILD b/test/e2e/instrumentation/monitoring/BUILD index a712842964..9ccc20d813 100644 --- a/test/e2e/instrumentation/monitoring/BUILD +++ b/test/e2e/instrumentation/monitoring/BUILD @@ -29,6 +29,7 @@ go_library( "//staging/src/k8s.io/apimachinery/pkg/selection:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", "//staging/src/k8s.io/client-go/discovery:go_default_library", + "//staging/src/k8s.io/client-go/discovery/cached:go_default_library", "//staging/src/k8s.io/client-go/kubernetes:go_default_library", "//staging/src/k8s.io/metrics/pkg/client/custom_metrics:go_default_library", "//staging/src/k8s.io/metrics/pkg/client/external_metrics:go_default_library", diff --git a/test/e2e/instrumentation/monitoring/custom_metrics_stackdriver.go b/test/e2e/instrumentation/monitoring/custom_metrics_stackdriver.go index 6f586b6219..36bed14bc6 100644 --- a/test/e2e/instrumentation/monitoring/custom_metrics_stackdriver.go +++ b/test/e2e/instrumentation/monitoring/custom_metrics_stackdriver.go @@ -29,11 +29,13 @@ import ( gcm "google.golang.org/api/monitoring/v3" "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/selection" "k8s.io/client-go/discovery" "k8s.io/kubernetes/test/e2e/framework" + cmv1beta1 "k8s.io/metrics/pkg/apis/custom_metrics/v1beta1" customclient "k8s.io/metrics/pkg/client/custom_metrics" externalclient "k8s.io/metrics/pkg/client/external_metrics" ) @@ -57,8 +59,10 @@ var _ = instrumentation.SIGDescribe("Stackdriver Monitoring", func() { if err != nil { framework.Failf("Failed to load config: %s", err) } - customMetricsClient := customclient.NewForConfigOrDie(config) discoveryClient := discovery.NewDiscoveryClientForConfigOrDie(config) + apiVersionsGetter := customclient.NewAvailableAPIsGetter(discoveryClient) + restMapper := meta.NewDefaultRESTMapper([]schema.GroupVersion{cmv1beta1.SchemeGroupVersion}) + customMetricsClient := customclient.NewForConfig(config, restMapper, apiVersionsGetter) testCustomMetrics(f, kubeClient, customMetricsClient, discoveryClient, AdapterForOldResourceModel) }) @@ -68,8 +72,10 @@ var _ = instrumentation.SIGDescribe("Stackdriver Monitoring", func() { if err != nil { framework.Failf("Failed to load config: %s", err) } - customMetricsClient := customclient.NewForConfigOrDie(config) discoveryClient := discovery.NewDiscoveryClientForConfigOrDie(config) + apiVersionsGetter := customclient.NewAvailableAPIsGetter(discoveryClient) + restMapper := meta.NewDefaultRESTMapper([]schema.GroupVersion{cmv1beta1.SchemeGroupVersion}) + customMetricsClient := customclient.NewForConfig(config, restMapper, apiVersionsGetter) testCustomMetrics(f, kubeClient, customMetricsClient, discoveryClient, AdapterForNewResourceModel) })