github.com/kubewharf/katalyst-core@v0.5.3/pkg/agent/sysadvisor/plugin/qosaware/resource/resource.go (about)

     1  /*
     2  Copyright 2022 The Katalyst Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package resource
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  
    23  	v1 "k8s.io/api/core/v1"
    24  	"k8s.io/apimachinery/pkg/api/resource"
    25  
    26  	"github.com/kubewharf/katalyst-core/pkg/agent/sysadvisor/metacache"
    27  	"github.com/kubewharf/katalyst-core/pkg/agent/sysadvisor/plugin/qosaware/resource/cpu"
    28  	"github.com/kubewharf/katalyst-core/pkg/agent/sysadvisor/plugin/qosaware/resource/memory"
    29  	"github.com/kubewharf/katalyst-core/pkg/agent/sysadvisor/types"
    30  	"github.com/kubewharf/katalyst-core/pkg/config"
    31  	"github.com/kubewharf/katalyst-core/pkg/metaserver"
    32  	"github.com/kubewharf/katalyst-core/pkg/metrics"
    33  )
    34  
    35  // ResourceAdvisor is a wrapper of different sub resource advisors. It can be registered to
    36  // headroom reporter to give designated resource headroom quantity based on provision result.
    37  type ResourceAdvisor interface {
    38  	// Run starts all sub resource advisors
    39  	Run(ctx context.Context)
    40  
    41  	// GetSubAdvisor returns the corresponding sub advisor according to resource name
    42  	GetSubAdvisor(resourceName types.QoSResourceName) (SubResourceAdvisor, error)
    43  
    44  	// GetHeadroom returns the corresponding headroom quantity according to resource name
    45  	GetHeadroom(resourceName v1.ResourceName) (resource.Quantity, error)
    46  }
    47  
    48  // SubResourceAdvisor updates resource provision of a certain dimension based on the latest
    49  // system and workload snapshot(s), and returns provision advice or resource headroom quantity.
    50  // It should push updated results to the corresponding qrm server.
    51  type SubResourceAdvisor interface {
    52  	// Run starts resource provision update based on the latest system and workload snapshot(s)
    53  	Run(ctx context.Context)
    54  
    55  	// GetChannels returns two channels. The first one receives update trigger from qrm server.
    56  	// The other one sends the latest internal calculation result to qrm server.
    57  	GetChannels() (interface{}, interface{})
    58  
    59  	// GetHeadroom returns the latest resource headroom quantity for resource reporter
    60  	GetHeadroom() (resource.Quantity, error)
    61  }
    62  
    63  type resourceAdvisorWrapper struct {
    64  	subAdvisorsToRun map[types.QoSResourceName]SubResourceAdvisor
    65  }
    66  
    67  // NewResourceAdvisor returns a resource advisor wrapper instance, initializing all required
    68  // sub resource advisor according to config
    69  func NewResourceAdvisor(conf *config.Configuration, extraConf interface{}, metaCache metacache.MetaCache,
    70  	metaServer *metaserver.MetaServer, emitter metrics.MetricEmitter,
    71  ) (ResourceAdvisor, error) {
    72  	resourceAdvisor := resourceAdvisorWrapper{
    73  		subAdvisorsToRun: make(map[types.QoSResourceName]SubResourceAdvisor),
    74  	}
    75  
    76  	for _, resourceNameStr := range conf.ResourceAdvisors {
    77  		resourceName := types.QoSResourceName(resourceNameStr)
    78  		subAdvisor, err := NewSubResourceAdvisor(resourceName, conf, extraConf, metaCache, metaServer, emitter)
    79  		if err != nil {
    80  			return nil, fmt.Errorf("new sub resource advisor for %v failed: %v", resourceName, err)
    81  		}
    82  		resourceAdvisor.subAdvisorsToRun[resourceName] = subAdvisor
    83  	}
    84  
    85  	return &resourceAdvisor, nil
    86  }
    87  
    88  // NewSubResourceAdvisor returns a corresponding advisor according to resource name
    89  func NewSubResourceAdvisor(resourceName types.QoSResourceName, conf *config.Configuration, extraConf interface{},
    90  	metaCache metacache.MetaCache, metaServer *metaserver.MetaServer, emitter metrics.MetricEmitter,
    91  ) (SubResourceAdvisor, error) {
    92  	switch resourceName {
    93  	case types.QoSResourceCPU:
    94  		return cpu.NewCPUResourceAdvisor(conf, extraConf, metaCache, metaServer, emitter), nil
    95  	case types.QoSResourceMemory:
    96  		return memory.NewMemoryResourceAdvisor(conf, extraConf, metaCache, metaServer, emitter), nil
    97  	default:
    98  		return nil, fmt.Errorf("try to new sub resource advisor for unsupported resource %v", resourceName)
    99  	}
   100  }
   101  
   102  func (ra *resourceAdvisorWrapper) Run(ctx context.Context) {
   103  	for _, subAdvisor := range ra.subAdvisorsToRun {
   104  		go subAdvisor.Run(ctx)
   105  	}
   106  }
   107  
   108  func (ra *resourceAdvisorWrapper) GetSubAdvisor(resourceName types.QoSResourceName) (SubResourceAdvisor, error) {
   109  	if subAdvisor, ok := ra.subAdvisorsToRun[resourceName]; ok {
   110  		return subAdvisor, nil
   111  	}
   112  	return nil, fmt.Errorf("no sub resource advisor for %v", resourceName)
   113  }
   114  
   115  func (ra *resourceAdvisorWrapper) GetHeadroom(resourceName v1.ResourceName) (resource.Quantity, error) {
   116  	switch resourceName {
   117  	case v1.ResourceCPU:
   118  		return ra.getSubAdvisorHeadroom(types.QoSResourceCPU)
   119  	case v1.ResourceMemory:
   120  		return ra.getSubAdvisorHeadroom(types.QoSResourceMemory)
   121  	default:
   122  		return resource.Quantity{}, fmt.Errorf("illegal resource %v", resourceName)
   123  	}
   124  }
   125  
   126  func (ra *resourceAdvisorWrapper) getSubAdvisorHeadroom(resourceName types.QoSResourceName) (resource.Quantity, error) {
   127  	subAdvisor, ok := ra.subAdvisorsToRun[resourceName]
   128  	if !ok {
   129  		return resource.Quantity{}, fmt.Errorf("no sub resource advisor for %v", resourceName)
   130  	}
   131  	return subAdvisor.GetHeadroom()
   132  }