Files
weave-scope/probe/kubernetes/cronjob.go
Roland Schilter 3de06b5a09 Support controls in more k8s topologies (#3110)
* Refactor: func has already access to probeID

* Allow controls for more k8s topologies

Controls for nodes generally need to know about the probe that is in
control of them.

This PR appends the probe ID info to k8s topologies CronJob, DaemonSet,
Service, and StatefulSet. Therefore allowing plugins to append controls.

* Remove superfluous error check

* Add some tests to verify controls allowance
2018-03-16 12:39:57 -07:00

116 lines
3.3 KiB
Go

package kubernetes
import (
"fmt"
"time"
batchv1 "k8s.io/api/batch/v1"
batchv1beta1 "k8s.io/api/batch/v1beta1"
batchv2alpha1 "k8s.io/api/batch/v2alpha1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/types"
"github.com/weaveworks/scope/report"
)
// These constants are keys used in node metadata
const (
Schedule = report.KubernetesSchedule
Suspended = report.KubernetesSuspended
LastScheduled = report.KubernetesLastScheduled
ActiveJobs = report.KubernetesActiveJobs
)
// CronJob represents a Kubernetes cron job
type CronJob interface {
Meta
Selectors() ([]labels.Selector, error)
GetNode(probeID string) report.Node
}
type cronJob struct {
*batchv1beta1.CronJob
Meta
jobs []*batchv1.Job
}
// NewCronJob creates a new cron job. jobs should be all jobs, which will be filtered
// for those matching this cron job.
func NewCronJob(cji interface{}, jobs map[types.UID]*batchv1.Job) CronJob {
switch cj := cji.(type) {
case *batchv2alpha1.CronJob:
return newCronJob(upgradeCronJob(cj), jobs)
case *batchv1beta1.CronJob:
return newCronJob(cj, jobs)
default:
panic(fmt.Sprintf("interface conversion: interface{} is %T, not *batchv2alpha1.CronJob or *batchv1beta1.CronJob", cj))
}
}
func newCronJob(cj *batchv1beta1.CronJob, jobs map[types.UID]*batchv1.Job) CronJob {
myJobs := []*batchv1.Job{}
for _, o := range cj.Status.Active {
if j, ok := jobs[o.UID]; ok {
myJobs = append(myJobs, j)
}
}
return &cronJob{
CronJob: cj,
Meta: meta{cj.ObjectMeta},
jobs: myJobs,
}
}
func (cj *cronJob) Selectors() ([]labels.Selector, error) {
selectors := []labels.Selector{}
for _, j := range cj.jobs {
selector, err := metav1.LabelSelectorAsSelector(j.Spec.Selector)
if err != nil {
return nil, err
}
selectors = append(selectors, selector)
}
return selectors, nil
}
func (cj *cronJob) GetNode(probeID string) report.Node {
latest := map[string]string{
NodeType: "CronJob",
Schedule: cj.Spec.Schedule,
Suspended: fmt.Sprint(cj.Spec.Suspend != nil && *cj.Spec.Suspend), // nil -> false
ActiveJobs: fmt.Sprint(len(cj.jobs)),
report.ControlProbeID: probeID,
}
if cj.Status.LastScheduleTime != nil {
latest[LastScheduled] = cj.Status.LastScheduleTime.Format(time.RFC3339Nano)
}
return cj.MetaNode(report.MakeCronJobNodeID(cj.UID())).WithLatests(latest)
}
func upgradeCronJob(legacy *batchv2alpha1.CronJob) *batchv1beta1.CronJob {
jobTemplate := batchv1beta1.JobTemplateSpec{
ObjectMeta: legacy.Spec.JobTemplate.ObjectMeta,
Spec: legacy.Spec.JobTemplate.Spec,
}
spec := batchv1beta1.CronJobSpec{
Schedule: legacy.Spec.Schedule,
StartingDeadlineSeconds: legacy.Spec.StartingDeadlineSeconds,
ConcurrencyPolicy: batchv1beta1.ConcurrencyPolicy(legacy.Spec.ConcurrencyPolicy),
Suspend: legacy.Spec.Suspend,
JobTemplate: jobTemplate,
SuccessfulJobsHistoryLimit: legacy.Spec.SuccessfulJobsHistoryLimit,
FailedJobsHistoryLimit: legacy.Spec.FailedJobsHistoryLimit,
}
status := batchv1beta1.CronJobStatus{
Active: legacy.Status.Active,
LastScheduleTime: legacy.Status.LastScheduleTime,
}
return &batchv1beta1.CronJob{
TypeMeta: legacy.TypeMeta,
ObjectMeta: legacy.ObjectMeta,
Spec: spec,
Status: status,
}
}