Closed AmitKumarDas closed 2 years ago
// https://github.com/kubernetes-sigs/controller-runtime/
// til
//
// config is used to talk to apiserver
// scheme maps go structs to GVKs
// mapper maps GVKs to Resources
// codecs is used to create a REST client for a GVK
// pkg/client/config/config.go
//
// -- get config to talk to K8s API server
// -- sane QPS & burst configurations
// pkg/client/apiutil/apimachinery.go
//
// -- fetch latest discovery info
// -- get GVK for object only for single versioned GVK
// -- get the rest client for any GVK
// -- protobuf scheme only for native k8s resources
// pkg/client/apiutil/dynamicrestmapper.go
//
// dynamically discovers resource types at runtime
// pkg/client/client_cache.go
//
// -- fetch resources (old as well as new)
// -- a resource is composed of its client, gvk and RESTMapping
// pkg/client/client.go
//
// -- composes typed & unstruct clients
// -- creates the cache of common stuff like
// -- config, scheme, mapper, codecs, &
// -- resources keyed by GVK
// https://github.com/kubernetes-sigs/controller-runtime/
//
// pkg/client/example_test.go
c, err := client.New(config.GetConfigOrDie(), client.Options{})
pl := &corev1.PodList{}
err = c.List(context.Background(), pl, client.InNamespace("default"))
u := &unstructured.UnstructuredList{}
u.SetGroupVersionKind(schema.GroupVersionKind{
Group: "apps",
Kind: "DeploymentList",
Version: "v1",
})
_ = c.List(context.Background(), u)
pod := &corev1.Pod{}
_ = c.Get(context.Background(), client.ObjectKey{
Namespace: "namespace",
Name: "name",
}, pod)
pod.SetFinalizers(append(pod.GetFinalizers(), "new-finalizer"))
_ = c.Update(context.Background(), pod)
u := &unstructured.Unstructured{}
u.SetGroupVersionKind(schema.GroupVersionKind{
Group: "apps",
Kind: "Deployment",
Version: "v1",
})
_ = c.Get(context.Background(), client.ObjectKey{
Namespace: "namespace",
Name: "name",
}, u)
u.SetFinalizers(append(u.GetFinalizers(), "new-finalizer"))
_ = c.Update(context.Background(), u)
// Update status if diff
// Do a semantic deep equal since we compare resource quantities as well
// See https://github.com/kubernetes/apimachinery/issues/75
if apiequality.Semantic.DeepEqual(&oldStatus, &account.Status) == false {
err = r.Status().Update(ctx, account)
}
patch := []byte(`{"metadata":{"annotations":{"version": "v2"}}}`)
_ = c.Patch(context.Background(), &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Namespace: "namespace",
Name: "name",
},
}, client.RawPatch(types.StrategicMergePatchType, patch))
// patch status
u := &unstructured.Unstructured{}
u.Object = map[string]interface{}{
"metadata": map[string]interface{}{
"name": "foo",
"namespace": "namespace",
},
}
u.SetGroupVersionKind(schema.GroupVersionKind{
Group: "batch",
Version: "v1beta1",
Kind: "CronJob",
})
patch := []byte(fmt.Sprintf(
`{"status":{"lastScheduleTime":"%s"}}`,
time.Now().Format(time.RFC3339),
))
_ = c.Status().Patch(
context.Background(),
u,
client.RawPatch(types.MergePatchType, patch),
)
_ = c.DeleteAllOf(
context.Background(),
&corev1.Pod{},
client.InNamespace("foo"),
client.MatchingLabels{"app": "foo"},
)
// Using an unstructured Object
u := &unstructured.Unstructured{}
u.SetGroupVersionKind(schema.GroupVersionKind{
Group: "apps",
Kind: "Deployment",
Version: "v1",
})
_ = c.DeleteAllOf(
context.Background(),
u,
client.InNamespace("foo"),
client.MatchingLabels{"app": "foo"},
)
// This example shows how to set up and
// consume a field selector over a pod's
// volumes' secretName field
func ExampleFieldIndexer_secretName() {
// someIndexer is a FieldIndexer over a Cache
_ = someIndexer.IndexField(
context.TODO(),
&corev1.Pod{},
"spec.volumes.secret.secretName",
func(o client.Object) []string {
var res []string
for _, vol := range o.(*corev1.Pod).Spec.Volumes {
if vol.Secret == nil {
continue
}
// just return the raw field value
// indexer will take care of dealing with namespaces for us
res = append(res, vol.Secret.SecretName)
}
return res
})
// elsewhere (e.g. in your reconciler)
// derived from the reconcile.Request, for instance
mySecretName := "someSecret"
var podsWithSecrets corev1.PodList
_ = c.List(
context.Background(),
&podsWithSecrets,
client.MatchingFields{"spec.volumes.secret.secretName": mySecretName},
)
}
// list all child jobs in this namespace
// that belong to this CronJob
// use the List method to list the child jobs
// Notice that we use variadic options to set
// the namespace and field match
// field match is actually an index lookup
// that we set up below
var childJobs kbatch.JobList
err := r.List(
ctx,
&childJobs,
client.InNamespace(req.Namespace),
client.MatchingFields{jobOwnerKey: req.Name},
)
// The reconciler fetches all jobs owned by the
// cronjob. As our number of cronjobs increases,
// looking these up can become quite slow as we
// have to filter through all of them. For a
// more efficient lookup, these jobs will be
// indexed locally on the controller's name. A
// jobOwnerKey field is added to the cached job
// objects. This key references the owning
// controller and functions as the index.
// In order to allow our reconciler to quickly
// look up Jobs by their owner, we’ll need an
// index. We declare an index key that we can
// later use with the client as a pseudo-field
// name, and then describe how to extract the
// indexed value from the Job object. The indexer
// will automatically take care of namespaces for
// us, so we just have to extract the owner name
// if the Job has a CronJob owner.
// Additionally, we’ll inform the manager that this
// controller owns some Jobs, so that it will
// automatically call Reconcile on the underlying
// CronJob when a Job changes, is deleted, etc.
var (
jobOwnerKey = ".metadata.controller"
apiGVStr = batch.GroupVersion.String()
)
func (r *CronJobReconciler) SetupWithManager(mgr ctrl.Manager) error {
err := mgr.GetFieldIndexer().IndexField(
context.Background(),
&kbatch.Job{},
jobOwnerKey,
func(rawObj client.Object) []string {
// grab the job object, extract the owner...
job := rawObj.(*kbatch.Job)
owner := metav1.GetControllerOf(job)
if owner == nil {
return nil
}
// ...make sure it's a CronJob...
if owner.APIVersion != apiGVStr || owner.Kind != "CronJob" {
return nil
}
// ...and if so, return it
return []string{owner.Name}
},
)
return ctrl.NewControllerManagedBy(mgr).
For(&batch.CronJob{}).
Owns(&kbatch.Job{}).
Complete(r)
}