-
Notifications
You must be signed in to change notification settings - Fork 1
ProblemEnvironmentをリソースを元にschedulerする #46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c54129b
d488fa8
cda7453
9978140
7b7f3da
fd4d774
af9007f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,6 +19,7 @@ package controllers | |
| import ( | ||
| "context" | ||
| "sort" | ||
| "strconv" | ||
| "time" | ||
|
|
||
| metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
|
|
@@ -38,6 +39,10 @@ type ProblemEnvironmentReconciler struct { | |
| Scheme *runtime.Scheme | ||
| } | ||
|
|
||
| const ( | ||
| MAX_USED_PERCENT float64 = 100.0 | ||
| ) | ||
|
|
||
| //+kubebuilder:rbac:groups=netcon.janog.gr.jp,resources=problemenvironments,verbs=get;list;watch;update;patch | ||
| //+kubebuilder:rbac:groups=netcon.janog.gr.jp,resources=problemenvironments/status,verbs=get;update;patch | ||
| //+kubebuilder:rbac:groups=netcon.janog.gr.jp,resources=problems,verbs=get;list;watch | ||
|
|
@@ -100,6 +105,51 @@ func (r *ProblemEnvironmentReconciler) updateStatus( | |
| return ctrl.Result{}, nil | ||
| } | ||
|
|
||
| func (r *ProblemEnvironmentReconciler) electWorker( | ||
| ctx context.Context, | ||
| workers netconv1alpha1.WorkerList, | ||
| problemEnvironments netconv1alpha1.ProblemEnvironmentList, | ||
| ) string { | ||
| log := log.FromContext(ctx) | ||
|
|
||
| workerLength := len(workers.Items) | ||
| if workerLength == 0 { | ||
| return "" | ||
| } else if workerLength < 2 { | ||
| return workers.Items[0].Name | ||
| } | ||
|
|
||
| type WorkerResource struct { | ||
| Name string | ||
| // CPUUsedPercent float64 | ||
| // MemoryUsedPercent float64 | ||
| SumOfResourcesUsedPercent float64 | ||
| } | ||
| arr := make([]WorkerResource, 0, workerLength) | ||
| for i := 0; i < workerLength; i++ { | ||
| cpuUsedPct, err := strconv.ParseFloat(workers.Items[i].Status.WorkerInfo.CPUUsedPercent, 64) | ||
| if err != nil { | ||
| log.Error(err, "failed to parse CPUUsedPercent for worker election") | ||
| cpuUsedPct = MAX_USED_PERCENT | ||
| } | ||
| memoryUsedPercent, err := strconv.ParseFloat(workers.Items[i].Status.WorkerInfo.MemoryUsedPercent, 64) | ||
| if err != nil { | ||
| log.Error(err, "failed to parse MemoryUsedPercent for worker election") | ||
| memoryUsedPercent = MAX_USED_PERCENT | ||
| } | ||
| sumOfResourcesUsedPercent := cpuUsedPct + memoryUsedPercent | ||
|
|
||
| arr = append(arr, WorkerResource{workers.Items[i].Name, sumOfResourcesUsedPercent}) | ||
| } | ||
| sort.Slice(arr, func(i, j int) bool { | ||
| return arr[i].SumOfResourcesUsedPercent < arr[j].SumOfResourcesUsedPercent | ||
| }) | ||
|
|
||
| log.Info("electWorker : " + arr[0].Name) | ||
|
|
||
| return arr[0].Name | ||
| } | ||
|
|
||
| func (r *ProblemEnvironmentReconciler) schedule( | ||
| ctx context.Context, | ||
| problemEnvironment *netconv1alpha1.ProblemEnvironment, | ||
|
|
@@ -145,33 +195,17 @@ func (r *ProblemEnvironmentReconciler) schedule( | |
| // TODO: handle error | ||
| } | ||
|
|
||
| workerNameProbEnvCountsMap := make(map[string]int) | ||
| for i := 0; i < len(problemEnvironments.Items); i++ { | ||
| if problemEnvironments.Items[i].Spec.WorkerName != "" { | ||
| key := problemEnvironments.Items[i].Spec.WorkerName | ||
| workerNameProbEnvCountsMap[key] = workerNameProbEnvCountsMap[key] + 1 | ||
| } | ||
| } | ||
| // there is no key-value pairs when getting started | ||
| if len(workerNameProbEnvCountsMap) == 0 { | ||
| problemEnvironment.Spec.WorkerName = workers.Items[0].Name | ||
| electedWorkerName := r.electWorker(ctx, workers, problemEnvironments) | ||
|
|
||
| if electedWorkerName != "" { | ||
| problemEnvironment.Spec.WorkerName = electedWorkerName | ||
| } else { | ||
| type kv struct { | ||
| Key string | ||
| Value int | ||
| } | ||
| ss := make([]kv, 0, len(workerNameProbEnvCountsMap)) | ||
| for k, v := range workerNameProbEnvCountsMap { | ||
| ss = append(ss, kv{k, v}) | ||
| } | ||
| sort.Slice(ss, func(i, j int) bool { | ||
| return ss[i].Value < ss[j].Value | ||
| }) | ||
| problemEnvironment.Spec.WorkerName = ss[0].Key | ||
| log.V(1).Info("elected workerName " + problemEnvironment.Spec.WorkerName) | ||
| // TODO: statusの Scheduled = Falseに更新する | ||
| // 更新せずとも、再reconcileが走るので問題はないはず | ||
|
Comment on lines
+203
to
+204
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| message := "failed to elect worker for scheduling" | ||
| log.Info(message) | ||
|
Comment on lines
+205
to
+206
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. エラー時は特に何も更新せずに終えようと思ってましたが、この方針で良いですか?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Scheduledっていうstatusがあったような気がする?ので、それをFalseに更新して、reasonに「workerが無かったよ」的なコメントを入れておけばいい気がします!(そのまま更新しないで抜けてもしばらくするとresync期間後に再Reconcileが走るはずなのでそれで問題ないと思います!)
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Issue切って別のPRで回収して全然大丈夫です!
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
こっちを想定してました、下記対応のほうが丁寧なので、あとで直してみますね
|
||
| } | ||
|
|
||
| log.Info("scheduled", "newWorkerName", problemEnvironment.Spec.WorkerName) | ||
| return r.update(ctx, problemEnvironment, ctrl.Result{}) | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,7 @@ package controllers | |
| import ( | ||
| "context" | ||
| "os" | ||
| "strconv" | ||
| "time" | ||
|
|
||
| metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
|
|
@@ -15,6 +16,8 @@ import ( | |
| "sigs.k8s.io/controller-runtime/pkg/runtime/inject" | ||
|
|
||
| netconv1alpha1 "github.com/janog-netcon/netcon-problem-management-subsystem/api/v1alpha1" | ||
| cpu "github.com/shirou/gopsutil/v3/cpu" | ||
| mem "github.com/shirou/gopsutil/v3/mem" | ||
| ) | ||
|
|
||
| type HeartbeatAgent struct { | ||
|
|
@@ -104,9 +107,23 @@ func (a *HeartbeatAgent) Start(ctx context.Context) error { | |
| // TODO: resolve external IP address used by users to access | ||
| externalIPAddress := "..." | ||
|
|
||
| virtualMemory, err := mem.VirtualMemory() | ||
| if err != nil { | ||
| log.Error(err, "failed to get memoryUsedPercent") | ||
| continue | ||
| } | ||
|
|
||
| cpuUsedPercents, err := cpu.Percent(time.Minute, false) | ||
| if err != nil { | ||
| log.Error(err, "failed to get CPUUsedPercent") | ||
| continue | ||
| } | ||
|
|
||
| worker.Status.WorkerInfo = netconv1alpha1.WorkerInfo{ | ||
| Hostname: hostname, | ||
| ExternalIPAddress: externalIPAddress, | ||
| MemoryUsedPercent: strconv.FormatFloat(virtualMemory.UsedPercent, 'f', -1, 64), | ||
| CPUUsedPercent: strconv.FormatFloat(cpuUsedPercents[0], 'f', -1, 64), | ||
|
Comment on lines
+125
to
+126
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| } | ||
|
|
||
| if err := a.Status().Update(ctx, &worker); err != nil { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
stringじゃなくてfloatでもつのがいいかなと思います!
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ここfloatだとコンパイルが通らなかったので、なくなくstringにしてました
後でもう一度試してみます!
warningですね
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
調べてたら似たような議論が出てきましたね。
kubernetes-sigs/controller-tools#245
ななめ読みする感じだと、floatは環境によって精度が変わったりするからintの方がいいよって感じですかね
方針はお任せするので、stringでもintでもめう氏が良さそうな方でお願いします!