-
Notifications
You must be signed in to change notification settings - Fork 383
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Find the Orphan Service Plugin in k8s cluster
- Loading branch information
Showing
13 changed files
with
330 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package service | ||
|
||
import ( | ||
"fmt" | ||
|
||
corev1 "k8s.io/api/core/v1" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
|
||
"github.com/gocrane/crane/pkg/recommendation/framework" | ||
) | ||
|
||
// Filter out k8s resources that are not supported by the recommender. | ||
func (s *ServiceRecommender) Filter(ctx *framework.RecommendationContext) error { | ||
var err error | ||
|
||
// filter resource that not match objectIdentity | ||
if err = s.BaseRecommender.Filter(ctx); err != nil { | ||
return err | ||
} | ||
var svc corev1.Service | ||
if err = framework.ObjectConversion(ctx.Object, &svc); err != nil { | ||
return err | ||
} | ||
|
||
if svc.Spec.Type != corev1.ServiceTypeLoadBalancer { | ||
return fmt.Errorf("service: %v type: %s is not a LoadBalancer", ctx.Object.GetName(), svc.Spec.Type) | ||
} | ||
|
||
// filter Endpoints not empty | ||
var ep corev1.Endpoints | ||
if err = ctx.Client.Get(ctx.Context, client.ObjectKeyFromObject(ctx.Object), &ep); client.IgnoreNotFound(err) != nil { | ||
return err | ||
} | ||
for _, ss := range ep.Subsets { | ||
if len(ss.Addresses) != 0 { | ||
return fmt.Errorf("service: %v addresses: %v not empty", ctx.Object.GetName(), ss.Addresses) | ||
} | ||
if len(ss.NotReadyAddresses) != 0 { | ||
return fmt.Errorf("service: %v NotReadyAddresses: %v not empty", ctx.Object.GetName(), ss.NotReadyAddresses) | ||
} | ||
} | ||
|
||
if err = framework.RetrievePods(ctx); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package service | ||
|
||
import ( | ||
"github.com/gocrane/crane/pkg/recommendation/framework" | ||
) | ||
|
||
// Observe enhance the observability. | ||
func (s *ServiceRecommender) Observe(ctx *framework.RecommendationContext) error { | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package service | ||
|
||
import ( | ||
"fmt" | ||
"time" | ||
|
||
corev1 "k8s.io/api/core/v1" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/labels" | ||
"k8s.io/klog/v2" | ||
|
||
"github.com/gocrane/crane/pkg/metricnaming" | ||
"github.com/gocrane/crane/pkg/providers" | ||
"github.com/gocrane/crane/pkg/recommendation/framework" | ||
"github.com/gocrane/crane/pkg/utils" | ||
) | ||
|
||
const callerFormat = "ServiceRecommender-%s-%s" | ||
|
||
// CheckDataProviders in PrePrepare phase, will create data source provider via your recommendation config. | ||
func (s *ServiceRecommender) CheckDataProviders(ctx *framework.RecommendationContext) error { | ||
if err := s.BaseRecommender.CheckDataProviders(ctx); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (s *ServiceRecommender) CollectData(ctx *framework.RecommendationContext) error { | ||
if len(ctx.Pods) == 0 { | ||
return nil | ||
} | ||
|
||
var workloadRef *metav1.OwnerReference | ||
for _, pod := range ctx.Pods { | ||
workloadRef = utils.GetPodOwnerReference(ctx.Context, ctx.Client, &pod) | ||
if workloadRef != nil { | ||
break | ||
} | ||
} | ||
if workloadRef == nil { | ||
return fmt.Errorf("could not find all pod OwnerReferences for Service %s selector", ctx.Object.GetName()) | ||
} | ||
podName := utils.GetPodNameReg(workloadRef.Name, workloadRef.Kind) | ||
|
||
labelSelector := labels.SelectorFromSet(ctx.Identity.Labels) | ||
caller := fmt.Sprintf(callerFormat, klog.KObj(ctx.Recommendation), ctx.Recommendation.UID) | ||
timeNow := time.Now() | ||
metricNamer := metricnaming.ResourceToGeneralMetricNamer(utils.GetWorkloadNetReceiveBytesExpression(podName), corev1.ResourceServices, labelSelector, caller) | ||
if err := metricNamer.Validate(); err != nil { | ||
return err | ||
} | ||
ctx.MetricNamer = metricNamer | ||
|
||
// get pod net receive bytes | ||
klog.Infof("%s: %s NetReceiveBytes %s", ctx.String(), s.Name(), ctx.MetricNamer.BuildUniqueKey()) | ||
tsList, err := ctx.DataProviders[providers.PrometheusDataSource].QueryTimeSeries(ctx.MetricNamer, timeNow.Add(-time.Hour*24*7), timeNow, time.Minute) | ||
if err != nil { | ||
return fmt.Errorf("%s query pod net receive bytes historic metrics failed: %v ", s.Name(), err) | ||
} | ||
if len(tsList) != 1 { | ||
return fmt.Errorf("%s query pod net receive bytes historic metrics data is unexpected, List length is %d ", s.Name(), len(tsList)) | ||
} | ||
ctx.AddInputValue(netReceiveBytesKey, tsList) | ||
|
||
metricNamer = metricnaming.ResourceToGeneralMetricNamer(utils.GetWorkloadNetTransferBytesExpression(podName), corev1.ResourceServices, labelSelector, caller) | ||
if err = metricNamer.Validate(); err != nil { | ||
return err | ||
} | ||
|
||
// get pod net transfer bytes | ||
klog.Infof("%s: %s NetTransferBytes %s", ctx.String(), s.Name(), ctx.MetricNamer.BuildUniqueKey()) | ||
tsList, err = ctx.DataProviders[providers.PrometheusDataSource].QueryTimeSeries(ctx.MetricNamer, timeNow.Add(-time.Hour*24*7), timeNow, time.Minute) | ||
if err != nil { | ||
return fmt.Errorf("%s query pod net transfer bytes historic metrics failed: %v ", s.Name(), err) | ||
} | ||
if len(tsList) != 1 { | ||
return fmt.Errorf("%s query pod net transfer bytes historic metrics data is unexpected, List length is %d ", s.Name(), len(tsList)) | ||
} | ||
ctx.AddInputValue(netTransferBytesKey, tsList) | ||
|
||
return nil | ||
} | ||
|
||
func (s *ServiceRecommender) PostProcessing(ctx *framework.RecommendationContext) error { | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package service | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/gocrane/crane/pkg/common" | ||
"github.com/gocrane/crane/pkg/recommendation/framework" | ||
) | ||
|
||
func (s *ServiceRecommender) PreRecommend(ctx *framework.RecommendationContext) error { | ||
return nil | ||
} | ||
|
||
func (s *ServiceRecommender) Recommend(ctx *framework.RecommendationContext) error { | ||
if len(ctx.Pods) == 0 { | ||
ctx.Recommendation.Status.Action = "Delete" | ||
ctx.Recommendation.Status.Description = "It is a Orphan Service, Pod count is 0" | ||
return nil | ||
} | ||
|
||
// check if pod net receive bytes lt config value | ||
if netReceiveBytes := s.getMaxValue(s.netReceiveBytes, ctx.InputValue(netReceiveBytesKey)); netReceiveBytes > s.netReceiveBytes { | ||
return fmt.Errorf("Service %s is not a Orphan Service, because the config value is %f, but the pod net receive bytes is %f ", ctx.Object.GetName(), s.netReceiveBytes, netReceiveBytes) | ||
} | ||
|
||
// check if pod net transfer bytes lt config value | ||
if netTransferBytes := s.getMaxValue(s.netTransferBytes, ctx.InputValue(netTransferBytesKey)); netTransferBytes > s.netTransferBytes { | ||
return fmt.Errorf("Service %s is not a Orphan Service, because the config value is %f, but the pod net transfer bytes is %f ", ctx.Object.GetName(), s.netTransferBytes, netTransferBytes) | ||
} | ||
|
||
ctx.Recommendation.Status.Action = "Delete" | ||
ctx.Recommendation.Status.Description = "It is a Orphan Service, Pod net bytes low" | ||
return nil | ||
} | ||
|
||
// Policy add some logic for result of recommend phase. | ||
func (s *ServiceRecommender) Policy(ctx *framework.RecommendationContext) error { | ||
return nil | ||
} | ||
|
||
func (s *ServiceRecommender) getMaxValue(configValue float64, ts []*common.TimeSeries) float64 { | ||
if configValue == 0 { | ||
return configValue | ||
} | ||
var maxValue float64 | ||
for _, ss := range ts[0].Samples { | ||
if ss.Value > maxValue { | ||
maxValue = ss.Value | ||
} | ||
} | ||
return maxValue | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package service | ||
|
||
import ( | ||
analysisv1alph1 "github.com/gocrane/api/analysis/v1alpha1" | ||
"github.com/gocrane/crane/pkg/recommendation/config" | ||
"github.com/gocrane/crane/pkg/recommendation/recommender" | ||
"github.com/gocrane/crane/pkg/recommendation/recommender/apis" | ||
"github.com/gocrane/crane/pkg/recommendation/recommender/base" | ||
) | ||
|
||
const ( | ||
netReceiveBytesKey = "pod-net-receive-bytes" | ||
netTransferBytesKey = "pod-net-transfer-bytes" | ||
) | ||
|
||
var _ recommender.Recommender = &ServiceRecommender{} | ||
|
||
type ServiceRecommender struct { | ||
base.BaseRecommender | ||
netReceiveBytes float64 | ||
netTransferBytes float64 | ||
} | ||
|
||
func init() { | ||
recommender.RegisterRecommenderProvider(recommender.ServiceRecommender, NewServiceRecommender) | ||
} | ||
|
||
func (s *ServiceRecommender) Name() string { | ||
return recommender.ServiceRecommender | ||
} | ||
|
||
// NewServiceRecommender create a new service recommender. | ||
func NewServiceRecommender(recommender apis.Recommender, recommendationRule analysisv1alph1.RecommendationRule) (recommender.Recommender, error) { | ||
recommender = config.MergeRecommenderConfigFromRule(recommender, recommendationRule) | ||
|
||
netReceiveBytes, err := recommender.GetConfigFloat(netReceiveBytesKey, 0) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
netTransferBytes, err := recommender.GetConfigFloat(netTransferBytesKey, 0) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return &ServiceRecommender{ | ||
*base.NewBaseRecommender(recommender), | ||
netReceiveBytes, | ||
netTransferBytes, | ||
}, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.