Commit 94da8b8e authored by galal-hussein's avatar galal-hussein

update helm-controller

parent 553517e1
...@@ -61,6 +61,7 @@ replace ( ...@@ -61,6 +61,7 @@ replace (
) )
require ( require (
github.com/Azure/go-autorest v14.0.1+incompatible // indirect
github.com/NYTimes/gziphandler v1.1.1 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
github.com/bhendo/go-powershell v0.0.0-20190719160123-219e7fb4e41e // indirect github.com/bhendo/go-powershell v0.0.0-20190719160123-219e7fb4e41e // indirect
...@@ -100,11 +101,11 @@ require ( ...@@ -100,11 +101,11 @@ require (
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/rakelkar/gonetsh v0.0.0-20190719023240-501daadcadf8 // indirect github.com/rakelkar/gonetsh v0.0.0-20190719023240-501daadcadf8 // indirect
github.com/rancher/dynamiclistener v0.2.0 github.com/rancher/dynamiclistener v0.2.0
github.com/rancher/helm-controller v0.4.2-0.20200326195131-eb51d4fa9d8d github.com/rancher/helm-controller v0.5.0
github.com/rancher/kine v0.3.5 github.com/rancher/kine v0.3.5
github.com/rancher/remotedialer v0.2.0 github.com/rancher/remotedialer v0.2.0
github.com/rancher/wrangler v0.5.4-0.20200326191509-4054411d9736 github.com/rancher/wrangler v0.6.1
github.com/rancher/wrangler-api v0.5.1-0.20200326194427-c13310506d04 github.com/rancher/wrangler-api v0.6.0
github.com/rootless-containers/rootlesskit v0.7.2 github.com/rootless-containers/rootlesskit v0.7.2
github.com/sirupsen/logrus v1.4.2 github.com/sirupsen/logrus v1.4.2
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
......
...@@ -7,6 +7,10 @@ github.com/Azure/azure-sdk-for-go v35.0.0+incompatible h1:PkmdmQUmeSdQQ5258f4SyC ...@@ -7,6 +7,10 @@ github.com/Azure/azure-sdk-for-go v35.0.0+incompatible h1:PkmdmQUmeSdQQ5258f4SyC
github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-autorest v11.1.2+incompatible h1:viZ3tV5l4gE2Sw0xrasFHytCGtzYCrT+um/rrSQ1BfA=
github.com/Azure/go-autorest v11.1.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest v14.0.1+incompatible h1:YhojO9jolWIvvTW7ORhz2ZSNF6Q1TbLqUunKd3jrtyw=
github.com/Azure/go-autorest v14.0.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.9.0 h1:MRvx8gncNaXJqOoLmhNjUAKh33JJF8LyxPhomEtOsjs= github.com/Azure/go-autorest/autorest v0.9.0 h1:MRvx8gncNaXJqOoLmhNjUAKh33JJF8LyxPhomEtOsjs=
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
github.com/Azure/go-autorest/autorest/adal v0.5.0 h1:q2gDruN08/guU9vAjuPWff0+QIrpH6ediguzdAzXAUU= github.com/Azure/go-autorest/autorest/adal v0.5.0 h1:q2gDruN08/guU9vAjuPWff0+QIrpH6ediguzdAzXAUU=
...@@ -640,6 +644,8 @@ github.com/rancher/flannel v0.11.0-k3s.2 h1:0GVr5ORAIvcri1LYTE8eMQ+NrRbuPeIniPaW ...@@ -640,6 +644,8 @@ github.com/rancher/flannel v0.11.0-k3s.2 h1:0GVr5ORAIvcri1LYTE8eMQ+NrRbuPeIniPaW
github.com/rancher/flannel v0.11.0-k3s.2/go.mod h1:Hn4ZV+eq0LhLZP63xZnxdGwXEoRSxs5sxELxu27M3UA= github.com/rancher/flannel v0.11.0-k3s.2/go.mod h1:Hn4ZV+eq0LhLZP63xZnxdGwXEoRSxs5sxELxu27M3UA=
github.com/rancher/helm-controller v0.4.2-0.20200326195131-eb51d4fa9d8d h1:6w5gCRgJzWEGdGi/0Xv4XXuGZY8wgWduRA9A+4c1N8I= github.com/rancher/helm-controller v0.4.2-0.20200326195131-eb51d4fa9d8d h1:6w5gCRgJzWEGdGi/0Xv4XXuGZY8wgWduRA9A+4c1N8I=
github.com/rancher/helm-controller v0.4.2-0.20200326195131-eb51d4fa9d8d/go.mod h1:3jCGmvjp3bFnbeuHL4HiODje9ZYJ/ujUBNtXHFXrwlM= github.com/rancher/helm-controller v0.4.2-0.20200326195131-eb51d4fa9d8d/go.mod h1:3jCGmvjp3bFnbeuHL4HiODje9ZYJ/ujUBNtXHFXrwlM=
github.com/rancher/helm-controller v0.5.0 h1:BY5PG3dz6GWct2O9r8mFv73tZ7E5U9uI89QwMBXV83E=
github.com/rancher/helm-controller v0.5.0/go.mod h1:kEtAI/0AylXIplxWkIRR2xl3nhd4jZ6Wke1nvE/sKUs=
github.com/rancher/kine v0.3.5 h1:Tm4eOtejpnzs1WFBrXj76lCLvX9czLlTkgqUk9luCQk= github.com/rancher/kine v0.3.5 h1:Tm4eOtejpnzs1WFBrXj76lCLvX9czLlTkgqUk9luCQk=
github.com/rancher/kine v0.3.5/go.mod h1:xEMl0tLCva9/9me7mXJ3m9Vo6yqHgC4OU3NiK4CPrGQ= github.com/rancher/kine v0.3.5/go.mod h1:xEMl0tLCva9/9me7mXJ3m9Vo6yqHgC4OU3NiK4CPrGQ=
github.com/rancher/kubernetes v1.18.2-k3s.1 h1:LhWNObWF7dL/+T57LkYpuRKtsCBpt0P5G6dRVFG+Ncs= github.com/rancher/kubernetes v1.18.2-k3s.1 h1:LhWNObWF7dL/+T57LkYpuRKtsCBpt0P5G6dRVFG+Ncs=
...@@ -693,9 +699,14 @@ github.com/rancher/wrangler v0.4.0 h1:iLvuJcZkd38E3RGG74dFMMNEju0PeTzfT1PQiv5okV ...@@ -693,9 +699,14 @@ github.com/rancher/wrangler v0.4.0 h1:iLvuJcZkd38E3RGG74dFMMNEju0PeTzfT1PQiv5okV
github.com/rancher/wrangler v0.4.0/go.mod h1:1cR91WLhZgkZ+U4fV9nVuXqKurWbgXcIReU4wnQvTN8= github.com/rancher/wrangler v0.4.0/go.mod h1:1cR91WLhZgkZ+U4fV9nVuXqKurWbgXcIReU4wnQvTN8=
github.com/rancher/wrangler v0.5.4-0.20200326191509-4054411d9736 h1:hqpVLgNUxU5sQUV6SzJPMY8Fy7T9Qht2QkA2Q7O/SH0= github.com/rancher/wrangler v0.5.4-0.20200326191509-4054411d9736 h1:hqpVLgNUxU5sQUV6SzJPMY8Fy7T9Qht2QkA2Q7O/SH0=
github.com/rancher/wrangler v0.5.4-0.20200326191509-4054411d9736/go.mod h1:L4HtjPeX8iqLgsxfJgz+JjKMcX2q3qbRXSeTlC/CSd4= github.com/rancher/wrangler v0.5.4-0.20200326191509-4054411d9736/go.mod h1:L4HtjPeX8iqLgsxfJgz+JjKMcX2q3qbRXSeTlC/CSd4=
github.com/rancher/wrangler v0.6.0/go.mod h1:L4HtjPeX8iqLgsxfJgz+JjKMcX2q3qbRXSeTlC/CSd4=
github.com/rancher/wrangler v0.6.1 h1:7tyLk/FV2zCQkYg5SEtT4lSlsHNwa5yMOa797/VJhiQ=
github.com/rancher/wrangler v0.6.1/go.mod h1:L4HtjPeX8iqLgsxfJgz+JjKMcX2q3qbRXSeTlC/CSd4=
github.com/rancher/wrangler-api v0.2.0/go.mod h1:zTPdNLZO07KvRaVOx6XQbKBSV55Fnn4s7nqmrMPJqd8= github.com/rancher/wrangler-api v0.2.0/go.mod h1:zTPdNLZO07KvRaVOx6XQbKBSV55Fnn4s7nqmrMPJqd8=
github.com/rancher/wrangler-api v0.5.1-0.20200326194427-c13310506d04 h1:y55e+kUaz/UswjN/oJdqHWMuoCG1FxwZJkxJEUONZZE= github.com/rancher/wrangler-api v0.5.1-0.20200326194427-c13310506d04 h1:y55e+kUaz/UswjN/oJdqHWMuoCG1FxwZJkxJEUONZZE=
github.com/rancher/wrangler-api v0.5.1-0.20200326194427-c13310506d04/go.mod h1:R3nemXoECcrDqXDSHdY7yJay4j42TeEkU79Hep0rdJ8= github.com/rancher/wrangler-api v0.5.1-0.20200326194427-c13310506d04/go.mod h1:R3nemXoECcrDqXDSHdY7yJay4j42TeEkU79Hep0rdJ8=
github.com/rancher/wrangler-api v0.6.0 h1:d/b0AkgZ+x41EYLIcUJiogtU3Y11Mqss2zr9VEKycRk=
github.com/rancher/wrangler-api v0.6.0/go.mod h1:RbuDkPNHhxcXuwAbLVvEAhH+UPAh+MIkpEd2fcGc0MM=
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
github.com/robfig/cron v1.1.0 h1:jk4/Hud3TTdcrJgUOBgsqrZBarcxl6ADIjSC2iniwLY= github.com/robfig/cron v1.1.0 h1:jk4/Hud3TTdcrJgUOBgsqrZBarcxl6ADIjSC2iniwLY=
github.com/robfig/cron v1.1.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= github.com/robfig/cron v1.1.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
......
...@@ -39,9 +39,10 @@ type Controller struct { ...@@ -39,9 +39,10 @@ type Controller struct {
} }
const ( const (
image = "rancher/klipper-helm:v0.2.3" image = "rancher/klipper-helm:v0.2.5"
label = "helmcharts.helm.cattle.io/chart" Label = "helmcharts.helm.cattle.io/chart"
name = "helm-controller" CRDName = "helmcharts.helm.cattle.io"
Name = "helm-controller"
) )
func Register(ctx context.Context, apply apply.Apply, func Register(ctx context.Context, apply apply.Apply,
...@@ -50,7 +51,7 @@ func Register(ctx context.Context, apply apply.Apply, ...@@ -50,7 +51,7 @@ func Register(ctx context.Context, apply apply.Apply,
crbs rbaccontroller.ClusterRoleBindingController, crbs rbaccontroller.ClusterRoleBindingController,
sas corecontroller.ServiceAccountController, sas corecontroller.ServiceAccountController,
cm corecontroller.ConfigMapController) { cm corecontroller.ConfigMapController) {
apply = apply.WithSetID(name). apply = apply.WithSetID(Name).
WithCacheTypes(helms, jobs, crbs, sas, cm). WithCacheTypes(helms, jobs, crbs, sas, cm).
WithStrictCaching().WithPatcher(batch.SchemeGroupVersion.WithKind("Job"), func(namespace, name string, pt types.PatchType, data []byte) (runtime.Object, error) { WithStrictCaching().WithPatcher(batch.SchemeGroupVersion.WithKind("Job"), func(namespace, name string, pt types.PatchType, data []byte) (runtime.Object, error) {
err := jobs.Delete(namespace, name, &metav1.DeleteOptions{}) err := jobs.Delete(namespace, name, &metav1.DeleteOptions{})
...@@ -63,7 +64,7 @@ func Register(ctx context.Context, apply apply.Apply, ...@@ -63,7 +64,7 @@ func Register(ctx context.Context, apply apply.Apply,
relatedresource.Watch(ctx, "helm-pod-watch", relatedresource.Watch(ctx, "helm-pod-watch",
func(namespace, name string, obj runtime.Object) ([]relatedresource.Key, error) { func(namespace, name string, obj runtime.Object) ([]relatedresource.Key, error) {
if job, ok := obj.(*batch.Job); ok { if job, ok := obj.(*batch.Job); ok {
name := job.Labels[label] name := job.Labels[Label]
if name != "" { if name != "" {
return []relatedresource.Key{ return []relatedresource.Key{
{ {
...@@ -84,8 +85,8 @@ func Register(ctx context.Context, apply apply.Apply, ...@@ -84,8 +85,8 @@ func Register(ctx context.Context, apply apply.Apply,
apply: apply, apply: apply,
} }
helms.OnChange(ctx, name, controller.OnHelmChanged) helms.OnChange(ctx, Name, controller.OnHelmChanged)
helms.OnRemove(ctx, name, controller.OnHelmRemove) helms.OnRemove(ctx, Name, controller.OnHelmRemove)
} }
func (c *Controller) OnHelmChanged(key string, chart *helmv1.HelmChart) (*helmv1.HelmChart, error) { func (c *Controller) OnHelmChanged(key string, chart *helmv1.HelmChart) (*helmv1.HelmChart, error) {
...@@ -163,7 +164,7 @@ func job(chart *helmv1.HelmChart) (*batch.Job, *core.ConfigMap) { ...@@ -163,7 +164,7 @@ func job(chart *helmv1.HelmChart) (*batch.Job, *core.ConfigMap) {
Name: fmt.Sprintf("helm-%s-%s", action, chart.Name), Name: fmt.Sprintf("helm-%s-%s", action, chart.Name),
Namespace: chart.Namespace, Namespace: chart.Namespace,
Labels: map[string]string{ Labels: map[string]string{
label: chart.Name, Label: chart.Name,
}, },
}, },
Spec: batch.JobSpec{ Spec: batch.JobSpec{
...@@ -171,7 +172,7 @@ func job(chart *helmv1.HelmChart) (*batch.Job, *core.ConfigMap) { ...@@ -171,7 +172,7 @@ func job(chart *helmv1.HelmChart) (*batch.Job, *core.ConfigMap) {
Template: core.PodTemplateSpec{ Template: core.PodTemplateSpec{
ObjectMeta: meta.ObjectMeta{ ObjectMeta: meta.ObjectMeta{
Labels: map[string]string{ Labels: map[string]string{
label: chart.Name, Label: chart.Name,
}, },
}, },
Spec: core.PodSpec{ Spec: core.PodSpec{
......
...@@ -52,18 +52,23 @@ func NewFactoryFromConfigOrDie(config *rest.Config) *Factory { ...@@ -52,18 +52,23 @@ func NewFactoryFromConfigOrDie(config *rest.Config) *Factory {
} }
func NewFactoryFromConfig(config *rest.Config) (*Factory, error) { func NewFactoryFromConfig(config *rest.Config) (*Factory, error) {
cs, err := clientset.NewForConfig(config) return NewFactoryFromConfigWithOptions(config, nil)
if err != nil {
return nil, err
}
informerFactory := informers.NewSharedInformerFactory(cs, 2*time.Hour)
return NewFactory(cs, informerFactory), nil
} }
func NewFactoryFromConfigWithNamespace(config *rest.Config, namespace string) (*Factory, error) { func NewFactoryFromConfigWithNamespace(config *rest.Config, namespace string) (*Factory, error) {
if namespace == "" { return NewFactoryFromConfigWithOptions(config, &FactoryOptions{
return NewFactoryFromConfig(config) Namespace: namespace,
})
}
type FactoryOptions struct {
Namespace string
Resync time.Duration
}
func NewFactoryFromConfigWithOptions(config *rest.Config, opts *FactoryOptions) (*Factory, error) {
if opts == nil {
opts = &FactoryOptions{}
} }
cs, err := clientset.NewForConfig(config) cs, err := clientset.NewForConfig(config)
...@@ -71,7 +76,17 @@ func NewFactoryFromConfigWithNamespace(config *rest.Config, namespace string) (* ...@@ -71,7 +76,17 @@ func NewFactoryFromConfigWithNamespace(config *rest.Config, namespace string) (*
return nil, err return nil, err
} }
informerFactory := informers.NewSharedInformerFactoryWithOptions(cs, 2*time.Hour, informers.WithNamespace(namespace)) resync := opts.Resync
if resync == 0 {
resync = 2 * time.Hour
}
if opts.Namespace == "" {
informerFactory := informers.NewSharedInformerFactory(cs, resync)
return NewFactory(cs, informerFactory), nil
}
informerFactory := informers.NewSharedInformerFactoryWithOptions(cs, resync, informers.WithNamespace(opts.Namespace))
return NewFactory(cs, informerFactory), nil return NewFactory(cs, informerFactory), nil
} }
......
...@@ -25,6 +25,7 @@ import ( ...@@ -25,6 +25,7 @@ import (
"github.com/rancher/wrangler/pkg/apply" "github.com/rancher/wrangler/pkg/apply"
"github.com/rancher/wrangler/pkg/condition" "github.com/rancher/wrangler/pkg/condition"
"github.com/rancher/wrangler/pkg/generic" "github.com/rancher/wrangler/pkg/generic"
"github.com/rancher/wrangler/pkg/kv"
v1 "k8s.io/api/apps/v1" v1 "k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
...@@ -267,6 +268,7 @@ func RegisterDaemonSetGeneratingHandler(ctx context.Context, controller DaemonSe ...@@ -267,6 +268,7 @@ func RegisterDaemonSetGeneratingHandler(ctx context.Context, controller DaemonSe
if opts != nil { if opts != nil {
statusHandler.opts = *opts statusHandler.opts = *opts
} }
controller.OnChange(ctx, name, statusHandler.Remove)
RegisterDaemonSetStatusHandler(ctx, controller, condition, name, statusHandler.Handle) RegisterDaemonSetStatusHandler(ctx, controller, condition, name, statusHandler.Handle)
} }
...@@ -281,7 +283,7 @@ func (a *daemonSetStatusHandler) sync(key string, obj *v1.DaemonSet) (*v1.Daemon ...@@ -281,7 +283,7 @@ func (a *daemonSetStatusHandler) sync(key string, obj *v1.DaemonSet) (*v1.Daemon
return obj, nil return obj, nil
} }
origStatus := obj.Status origStatus := obj.Status.DeepCopy()
obj = obj.DeepCopy() obj = obj.DeepCopy()
newStatus, err := a.handler(obj, obj.Status) newStatus, err := a.handler(obj, obj.Status)
if err != nil { if err != nil {
...@@ -289,16 +291,16 @@ func (a *daemonSetStatusHandler) sync(key string, obj *v1.DaemonSet) (*v1.Daemon ...@@ -289,16 +291,16 @@ func (a *daemonSetStatusHandler) sync(key string, obj *v1.DaemonSet) (*v1.Daemon
newStatus = *origStatus.DeepCopy() newStatus = *origStatus.DeepCopy()
} }
obj.Status = newStatus
if a.condition != "" { if a.condition != "" {
if errors.IsConflict(err) { if errors.IsConflict(err) {
a.condition.SetError(obj, "", nil) a.condition.SetError(&newStatus, "", nil)
} else { } else {
a.condition.SetError(obj, "", err) a.condition.SetError(&newStatus, "", err)
} }
} }
if !equality.Semantic.DeepEqual(origStatus, obj.Status) { if !equality.Semantic.DeepEqual(origStatus, &newStatus) {
var newErr error var newErr error
obj.Status = newStatus
obj, newErr = a.client.UpdateStatus(obj) obj, newErr = a.client.UpdateStatus(obj)
if err == nil { if err == nil {
err = newErr err = newErr
...@@ -315,29 +317,28 @@ type daemonSetGeneratingHandler struct { ...@@ -315,29 +317,28 @@ type daemonSetGeneratingHandler struct {
name string name string
} }
func (a *daemonSetGeneratingHandler) Handle(obj *v1.DaemonSet, status v1.DaemonSetStatus) (v1.DaemonSetStatus, error) { func (a *daemonSetGeneratingHandler) Remove(key string, obj *v1.DaemonSet) (*v1.DaemonSet, error) {
objs, newStatus, err := a.DaemonSetGeneratingHandler(obj, status) if obj != nil {
if err != nil { return obj, nil
return newStatus, err
} }
apply := a.apply obj = &v1.DaemonSet{}
obj.Namespace, obj.Name = kv.RSplit(key, "/")
if !a.opts.DynamicLookup { obj.SetGroupVersionKind(a.gvk)
apply = apply.WithStrictCaching()
}
if !a.opts.AllowCrossNamespace && !a.opts.AllowClusterScoped { return nil, generic.ConfigureApplyForObject(a.apply, obj, &a.opts).
apply = apply.WithSetOwnerReference(true, false). WithOwner(obj).
WithDefaultNamespace(obj.GetNamespace()). WithSetID(a.name).
WithListerNamespace(obj.GetNamespace()) ApplyObjects()
} }
if !a.opts.AllowClusterScoped { func (a *daemonSetGeneratingHandler) Handle(obj *v1.DaemonSet, status v1.DaemonSetStatus) (v1.DaemonSetStatus, error) {
apply = apply.WithRestrictClusterScoped() objs, newStatus, err := a.DaemonSetGeneratingHandler(obj, status)
if err != nil {
return newStatus, err
} }
return newStatus, apply. return newStatus, generic.ConfigureApplyForObject(a.apply, obj, &a.opts).
WithOwner(obj). WithOwner(obj).
WithSetID(a.name). WithSetID(a.name).
ApplyObjects(objs...) ApplyObjects(objs...)
......
...@@ -25,6 +25,7 @@ import ( ...@@ -25,6 +25,7 @@ import (
"github.com/rancher/wrangler/pkg/apply" "github.com/rancher/wrangler/pkg/apply"
"github.com/rancher/wrangler/pkg/condition" "github.com/rancher/wrangler/pkg/condition"
"github.com/rancher/wrangler/pkg/generic" "github.com/rancher/wrangler/pkg/generic"
"github.com/rancher/wrangler/pkg/kv"
v1 "k8s.io/api/apps/v1" v1 "k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
...@@ -267,6 +268,7 @@ func RegisterDeploymentGeneratingHandler(ctx context.Context, controller Deploym ...@@ -267,6 +268,7 @@ func RegisterDeploymentGeneratingHandler(ctx context.Context, controller Deploym
if opts != nil { if opts != nil {
statusHandler.opts = *opts statusHandler.opts = *opts
} }
controller.OnChange(ctx, name, statusHandler.Remove)
RegisterDeploymentStatusHandler(ctx, controller, condition, name, statusHandler.Handle) RegisterDeploymentStatusHandler(ctx, controller, condition, name, statusHandler.Handle)
} }
...@@ -281,7 +283,7 @@ func (a *deploymentStatusHandler) sync(key string, obj *v1.Deployment) (*v1.Depl ...@@ -281,7 +283,7 @@ func (a *deploymentStatusHandler) sync(key string, obj *v1.Deployment) (*v1.Depl
return obj, nil return obj, nil
} }
origStatus := obj.Status origStatus := obj.Status.DeepCopy()
obj = obj.DeepCopy() obj = obj.DeepCopy()
newStatus, err := a.handler(obj, obj.Status) newStatus, err := a.handler(obj, obj.Status)
if err != nil { if err != nil {
...@@ -289,16 +291,16 @@ func (a *deploymentStatusHandler) sync(key string, obj *v1.Deployment) (*v1.Depl ...@@ -289,16 +291,16 @@ func (a *deploymentStatusHandler) sync(key string, obj *v1.Deployment) (*v1.Depl
newStatus = *origStatus.DeepCopy() newStatus = *origStatus.DeepCopy()
} }
obj.Status = newStatus
if a.condition != "" { if a.condition != "" {
if errors.IsConflict(err) { if errors.IsConflict(err) {
a.condition.SetError(obj, "", nil) a.condition.SetError(&newStatus, "", nil)
} else { } else {
a.condition.SetError(obj, "", err) a.condition.SetError(&newStatus, "", err)
} }
} }
if !equality.Semantic.DeepEqual(origStatus, obj.Status) { if !equality.Semantic.DeepEqual(origStatus, &newStatus) {
var newErr error var newErr error
obj.Status = newStatus
obj, newErr = a.client.UpdateStatus(obj) obj, newErr = a.client.UpdateStatus(obj)
if err == nil { if err == nil {
err = newErr err = newErr
...@@ -315,29 +317,28 @@ type deploymentGeneratingHandler struct { ...@@ -315,29 +317,28 @@ type deploymentGeneratingHandler struct {
name string name string
} }
func (a *deploymentGeneratingHandler) Handle(obj *v1.Deployment, status v1.DeploymentStatus) (v1.DeploymentStatus, error) { func (a *deploymentGeneratingHandler) Remove(key string, obj *v1.Deployment) (*v1.Deployment, error) {
objs, newStatus, err := a.DeploymentGeneratingHandler(obj, status) if obj != nil {
if err != nil { return obj, nil
return newStatus, err
} }
apply := a.apply obj = &v1.Deployment{}
obj.Namespace, obj.Name = kv.RSplit(key, "/")
if !a.opts.DynamicLookup { obj.SetGroupVersionKind(a.gvk)
apply = apply.WithStrictCaching()
}
if !a.opts.AllowCrossNamespace && !a.opts.AllowClusterScoped { return nil, generic.ConfigureApplyForObject(a.apply, obj, &a.opts).
apply = apply.WithSetOwnerReference(true, false). WithOwner(obj).
WithDefaultNamespace(obj.GetNamespace()). WithSetID(a.name).
WithListerNamespace(obj.GetNamespace()) ApplyObjects()
} }
if !a.opts.AllowClusterScoped { func (a *deploymentGeneratingHandler) Handle(obj *v1.Deployment, status v1.DeploymentStatus) (v1.DeploymentStatus, error) {
apply = apply.WithRestrictClusterScoped() objs, newStatus, err := a.DeploymentGeneratingHandler(obj, status)
if err != nil {
return newStatus, err
} }
return newStatus, apply. return newStatus, generic.ConfigureApplyForObject(a.apply, obj, &a.opts).
WithOwner(obj). WithOwner(obj).
WithSetID(a.name). WithSetID(a.name).
ApplyObjects(objs...) ApplyObjects(objs...)
......
...@@ -25,6 +25,7 @@ import ( ...@@ -25,6 +25,7 @@ import (
"github.com/rancher/wrangler/pkg/apply" "github.com/rancher/wrangler/pkg/apply"
"github.com/rancher/wrangler/pkg/condition" "github.com/rancher/wrangler/pkg/condition"
"github.com/rancher/wrangler/pkg/generic" "github.com/rancher/wrangler/pkg/generic"
"github.com/rancher/wrangler/pkg/kv"
v1 "k8s.io/api/apps/v1" v1 "k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
...@@ -267,6 +268,7 @@ func RegisterStatefulSetGeneratingHandler(ctx context.Context, controller Statef ...@@ -267,6 +268,7 @@ func RegisterStatefulSetGeneratingHandler(ctx context.Context, controller Statef
if opts != nil { if opts != nil {
statusHandler.opts = *opts statusHandler.opts = *opts
} }
controller.OnChange(ctx, name, statusHandler.Remove)
RegisterStatefulSetStatusHandler(ctx, controller, condition, name, statusHandler.Handle) RegisterStatefulSetStatusHandler(ctx, controller, condition, name, statusHandler.Handle)
} }
...@@ -281,7 +283,7 @@ func (a *statefulSetStatusHandler) sync(key string, obj *v1.StatefulSet) (*v1.St ...@@ -281,7 +283,7 @@ func (a *statefulSetStatusHandler) sync(key string, obj *v1.StatefulSet) (*v1.St
return obj, nil return obj, nil
} }
origStatus := obj.Status origStatus := obj.Status.DeepCopy()
obj = obj.DeepCopy() obj = obj.DeepCopy()
newStatus, err := a.handler(obj, obj.Status) newStatus, err := a.handler(obj, obj.Status)
if err != nil { if err != nil {
...@@ -289,16 +291,16 @@ func (a *statefulSetStatusHandler) sync(key string, obj *v1.StatefulSet) (*v1.St ...@@ -289,16 +291,16 @@ func (a *statefulSetStatusHandler) sync(key string, obj *v1.StatefulSet) (*v1.St
newStatus = *origStatus.DeepCopy() newStatus = *origStatus.DeepCopy()
} }
obj.Status = newStatus
if a.condition != "" { if a.condition != "" {
if errors.IsConflict(err) { if errors.IsConflict(err) {
a.condition.SetError(obj, "", nil) a.condition.SetError(&newStatus, "", nil)
} else { } else {
a.condition.SetError(obj, "", err) a.condition.SetError(&newStatus, "", err)
} }
} }
if !equality.Semantic.DeepEqual(origStatus, obj.Status) { if !equality.Semantic.DeepEqual(origStatus, &newStatus) {
var newErr error var newErr error
obj.Status = newStatus
obj, newErr = a.client.UpdateStatus(obj) obj, newErr = a.client.UpdateStatus(obj)
if err == nil { if err == nil {
err = newErr err = newErr
...@@ -315,29 +317,28 @@ type statefulSetGeneratingHandler struct { ...@@ -315,29 +317,28 @@ type statefulSetGeneratingHandler struct {
name string name string
} }
func (a *statefulSetGeneratingHandler) Handle(obj *v1.StatefulSet, status v1.StatefulSetStatus) (v1.StatefulSetStatus, error) { func (a *statefulSetGeneratingHandler) Remove(key string, obj *v1.StatefulSet) (*v1.StatefulSet, error) {
objs, newStatus, err := a.StatefulSetGeneratingHandler(obj, status) if obj != nil {
if err != nil { return obj, nil
return newStatus, err
} }
apply := a.apply obj = &v1.StatefulSet{}
obj.Namespace, obj.Name = kv.RSplit(key, "/")
if !a.opts.DynamicLookup { obj.SetGroupVersionKind(a.gvk)
apply = apply.WithStrictCaching()
}
if !a.opts.AllowCrossNamespace && !a.opts.AllowClusterScoped { return nil, generic.ConfigureApplyForObject(a.apply, obj, &a.opts).
apply = apply.WithSetOwnerReference(true, false). WithOwner(obj).
WithDefaultNamespace(obj.GetNamespace()). WithSetID(a.name).
WithListerNamespace(obj.GetNamespace()) ApplyObjects()
} }
if !a.opts.AllowClusterScoped { func (a *statefulSetGeneratingHandler) Handle(obj *v1.StatefulSet, status v1.StatefulSetStatus) (v1.StatefulSetStatus, error) {
apply = apply.WithRestrictClusterScoped() objs, newStatus, err := a.StatefulSetGeneratingHandler(obj, status)
if err != nil {
return newStatus, err
} }
return newStatus, apply. return newStatus, generic.ConfigureApplyForObject(a.apply, obj, &a.opts).
WithOwner(obj). WithOwner(obj).
WithSetID(a.name). WithSetID(a.name).
ApplyObjects(objs...) ApplyObjects(objs...)
......
...@@ -52,18 +52,23 @@ func NewFactoryFromConfigOrDie(config *rest.Config) *Factory { ...@@ -52,18 +52,23 @@ func NewFactoryFromConfigOrDie(config *rest.Config) *Factory {
} }
func NewFactoryFromConfig(config *rest.Config) (*Factory, error) { func NewFactoryFromConfig(config *rest.Config) (*Factory, error) {
cs, err := clientset.NewForConfig(config) return NewFactoryFromConfigWithOptions(config, nil)
if err != nil {
return nil, err
}
informerFactory := informers.NewSharedInformerFactory(cs, 2*time.Hour)
return NewFactory(cs, informerFactory), nil
} }
func NewFactoryFromConfigWithNamespace(config *rest.Config, namespace string) (*Factory, error) { func NewFactoryFromConfigWithNamespace(config *rest.Config, namespace string) (*Factory, error) {
if namespace == "" { return NewFactoryFromConfigWithOptions(config, &FactoryOptions{
return NewFactoryFromConfig(config) Namespace: namespace,
})
}
type FactoryOptions struct {
Namespace string
Resync time.Duration
}
func NewFactoryFromConfigWithOptions(config *rest.Config, opts *FactoryOptions) (*Factory, error) {
if opts == nil {
opts = &FactoryOptions{}
} }
cs, err := clientset.NewForConfig(config) cs, err := clientset.NewForConfig(config)
...@@ -71,7 +76,17 @@ func NewFactoryFromConfigWithNamespace(config *rest.Config, namespace string) (* ...@@ -71,7 +76,17 @@ func NewFactoryFromConfigWithNamespace(config *rest.Config, namespace string) (*
return nil, err return nil, err
} }
informerFactory := informers.NewSharedInformerFactoryWithOptions(cs, 2*time.Hour, informers.WithNamespace(namespace)) resync := opts.Resync
if resync == 0 {
resync = 2 * time.Hour
}
if opts.Namespace == "" {
informerFactory := informers.NewSharedInformerFactory(cs, resync)
return NewFactory(cs, informerFactory), nil
}
informerFactory := informers.NewSharedInformerFactoryWithOptions(cs, resync, informers.WithNamespace(opts.Namespace))
return NewFactory(cs, informerFactory), nil return NewFactory(cs, informerFactory), nil
} }
......
...@@ -25,6 +25,7 @@ import ( ...@@ -25,6 +25,7 @@ import (
"github.com/rancher/wrangler/pkg/apply" "github.com/rancher/wrangler/pkg/apply"
"github.com/rancher/wrangler/pkg/condition" "github.com/rancher/wrangler/pkg/condition"
"github.com/rancher/wrangler/pkg/generic" "github.com/rancher/wrangler/pkg/generic"
"github.com/rancher/wrangler/pkg/kv"
v1 "k8s.io/api/batch/v1" v1 "k8s.io/api/batch/v1"
"k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
...@@ -267,6 +268,7 @@ func RegisterJobGeneratingHandler(ctx context.Context, controller JobController, ...@@ -267,6 +268,7 @@ func RegisterJobGeneratingHandler(ctx context.Context, controller JobController,
if opts != nil { if opts != nil {
statusHandler.opts = *opts statusHandler.opts = *opts
} }
controller.OnChange(ctx, name, statusHandler.Remove)
RegisterJobStatusHandler(ctx, controller, condition, name, statusHandler.Handle) RegisterJobStatusHandler(ctx, controller, condition, name, statusHandler.Handle)
} }
...@@ -281,7 +283,7 @@ func (a *jobStatusHandler) sync(key string, obj *v1.Job) (*v1.Job, error) { ...@@ -281,7 +283,7 @@ func (a *jobStatusHandler) sync(key string, obj *v1.Job) (*v1.Job, error) {
return obj, nil return obj, nil
} }
origStatus := obj.Status origStatus := obj.Status.DeepCopy()
obj = obj.DeepCopy() obj = obj.DeepCopy()
newStatus, err := a.handler(obj, obj.Status) newStatus, err := a.handler(obj, obj.Status)
if err != nil { if err != nil {
...@@ -289,16 +291,16 @@ func (a *jobStatusHandler) sync(key string, obj *v1.Job) (*v1.Job, error) { ...@@ -289,16 +291,16 @@ func (a *jobStatusHandler) sync(key string, obj *v1.Job) (*v1.Job, error) {
newStatus = *origStatus.DeepCopy() newStatus = *origStatus.DeepCopy()
} }
obj.Status = newStatus
if a.condition != "" { if a.condition != "" {
if errors.IsConflict(err) { if errors.IsConflict(err) {
a.condition.SetError(obj, "", nil) a.condition.SetError(&newStatus, "", nil)
} else { } else {
a.condition.SetError(obj, "", err) a.condition.SetError(&newStatus, "", err)
} }
} }
if !equality.Semantic.DeepEqual(origStatus, obj.Status) { if !equality.Semantic.DeepEqual(origStatus, &newStatus) {
var newErr error var newErr error
obj.Status = newStatus
obj, newErr = a.client.UpdateStatus(obj) obj, newErr = a.client.UpdateStatus(obj)
if err == nil { if err == nil {
err = newErr err = newErr
...@@ -315,29 +317,28 @@ type jobGeneratingHandler struct { ...@@ -315,29 +317,28 @@ type jobGeneratingHandler struct {
name string name string
} }
func (a *jobGeneratingHandler) Handle(obj *v1.Job, status v1.JobStatus) (v1.JobStatus, error) { func (a *jobGeneratingHandler) Remove(key string, obj *v1.Job) (*v1.Job, error) {
objs, newStatus, err := a.JobGeneratingHandler(obj, status) if obj != nil {
if err != nil { return obj, nil
return newStatus, err
} }
apply := a.apply obj = &v1.Job{}
obj.Namespace, obj.Name = kv.RSplit(key, "/")
if !a.opts.DynamicLookup { obj.SetGroupVersionKind(a.gvk)
apply = apply.WithStrictCaching()
}
if !a.opts.AllowCrossNamespace && !a.opts.AllowClusterScoped { return nil, generic.ConfigureApplyForObject(a.apply, obj, &a.opts).
apply = apply.WithSetOwnerReference(true, false). WithOwner(obj).
WithDefaultNamespace(obj.GetNamespace()). WithSetID(a.name).
WithListerNamespace(obj.GetNamespace()) ApplyObjects()
} }
if !a.opts.AllowClusterScoped { func (a *jobGeneratingHandler) Handle(obj *v1.Job, status v1.JobStatus) (v1.JobStatus, error) {
apply = apply.WithRestrictClusterScoped() objs, newStatus, err := a.JobGeneratingHandler(obj, status)
if err != nil {
return newStatus, err
} }
return newStatus, apply. return newStatus, generic.ConfigureApplyForObject(a.apply, obj, &a.opts).
WithOwner(obj). WithOwner(obj).
WithSetID(a.name). WithSetID(a.name).
ApplyObjects(objs...) ApplyObjects(objs...)
......
...@@ -52,18 +52,23 @@ func NewFactoryFromConfigOrDie(config *rest.Config) *Factory { ...@@ -52,18 +52,23 @@ func NewFactoryFromConfigOrDie(config *rest.Config) *Factory {
} }
func NewFactoryFromConfig(config *rest.Config) (*Factory, error) { func NewFactoryFromConfig(config *rest.Config) (*Factory, error) {
cs, err := clientset.NewForConfig(config) return NewFactoryFromConfigWithOptions(config, nil)
if err != nil {
return nil, err
}
informerFactory := informers.NewSharedInformerFactory(cs, 2*time.Hour)
return NewFactory(cs, informerFactory), nil
} }
func NewFactoryFromConfigWithNamespace(config *rest.Config, namespace string) (*Factory, error) { func NewFactoryFromConfigWithNamespace(config *rest.Config, namespace string) (*Factory, error) {
if namespace == "" { return NewFactoryFromConfigWithOptions(config, &FactoryOptions{
return NewFactoryFromConfig(config) Namespace: namespace,
})
}
type FactoryOptions struct {
Namespace string
Resync time.Duration
}
func NewFactoryFromConfigWithOptions(config *rest.Config, opts *FactoryOptions) (*Factory, error) {
if opts == nil {
opts = &FactoryOptions{}
} }
cs, err := clientset.NewForConfig(config) cs, err := clientset.NewForConfig(config)
...@@ -71,7 +76,17 @@ func NewFactoryFromConfigWithNamespace(config *rest.Config, namespace string) (* ...@@ -71,7 +76,17 @@ func NewFactoryFromConfigWithNamespace(config *rest.Config, namespace string) (*
return nil, err return nil, err
} }
informerFactory := informers.NewSharedInformerFactoryWithOptions(cs, 2*time.Hour, informers.WithNamespace(namespace)) resync := opts.Resync
if resync == 0 {
resync = 2 * time.Hour
}
if opts.Namespace == "" {
informerFactory := informers.NewSharedInformerFactory(cs, resync)
return NewFactory(cs, informerFactory), nil
}
informerFactory := informers.NewSharedInformerFactoryWithOptions(cs, resync, informers.WithNamespace(opts.Namespace))
return NewFactory(cs, informerFactory), nil return NewFactory(cs, informerFactory), nil
} }
......
...@@ -25,6 +25,7 @@ import ( ...@@ -25,6 +25,7 @@ import (
"github.com/rancher/wrangler/pkg/apply" "github.com/rancher/wrangler/pkg/apply"
"github.com/rancher/wrangler/pkg/condition" "github.com/rancher/wrangler/pkg/condition"
"github.com/rancher/wrangler/pkg/generic" "github.com/rancher/wrangler/pkg/generic"
"github.com/rancher/wrangler/pkg/kv"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
...@@ -267,6 +268,7 @@ func RegisterNamespaceGeneratingHandler(ctx context.Context, controller Namespac ...@@ -267,6 +268,7 @@ func RegisterNamespaceGeneratingHandler(ctx context.Context, controller Namespac
if opts != nil { if opts != nil {
statusHandler.opts = *opts statusHandler.opts = *opts
} }
controller.OnChange(ctx, name, statusHandler.Remove)
RegisterNamespaceStatusHandler(ctx, controller, condition, name, statusHandler.Handle) RegisterNamespaceStatusHandler(ctx, controller, condition, name, statusHandler.Handle)
} }
...@@ -281,7 +283,7 @@ func (a *namespaceStatusHandler) sync(key string, obj *v1.Namespace) (*v1.Namesp ...@@ -281,7 +283,7 @@ func (a *namespaceStatusHandler) sync(key string, obj *v1.Namespace) (*v1.Namesp
return obj, nil return obj, nil
} }
origStatus := obj.Status origStatus := obj.Status.DeepCopy()
obj = obj.DeepCopy() obj = obj.DeepCopy()
newStatus, err := a.handler(obj, obj.Status) newStatus, err := a.handler(obj, obj.Status)
if err != nil { if err != nil {
...@@ -289,16 +291,16 @@ func (a *namespaceStatusHandler) sync(key string, obj *v1.Namespace) (*v1.Namesp ...@@ -289,16 +291,16 @@ func (a *namespaceStatusHandler) sync(key string, obj *v1.Namespace) (*v1.Namesp
newStatus = *origStatus.DeepCopy() newStatus = *origStatus.DeepCopy()
} }
obj.Status = newStatus
if a.condition != "" { if a.condition != "" {
if errors.IsConflict(err) { if errors.IsConflict(err) {
a.condition.SetError(obj, "", nil) a.condition.SetError(&newStatus, "", nil)
} else { } else {
a.condition.SetError(obj, "", err) a.condition.SetError(&newStatus, "", err)
} }
} }
if !equality.Semantic.DeepEqual(origStatus, obj.Status) { if !equality.Semantic.DeepEqual(origStatus, &newStatus) {
var newErr error var newErr error
obj.Status = newStatus
obj, newErr = a.client.UpdateStatus(obj) obj, newErr = a.client.UpdateStatus(obj)
if err == nil { if err == nil {
err = newErr err = newErr
...@@ -315,29 +317,28 @@ type namespaceGeneratingHandler struct { ...@@ -315,29 +317,28 @@ type namespaceGeneratingHandler struct {
name string name string
} }
func (a *namespaceGeneratingHandler) Handle(obj *v1.Namespace, status v1.NamespaceStatus) (v1.NamespaceStatus, error) { func (a *namespaceGeneratingHandler) Remove(key string, obj *v1.Namespace) (*v1.Namespace, error) {
objs, newStatus, err := a.NamespaceGeneratingHandler(obj, status) if obj != nil {
if err != nil { return obj, nil
return newStatus, err
} }
apply := a.apply obj = &v1.Namespace{}
obj.Namespace, obj.Name = kv.RSplit(key, "/")
if !a.opts.DynamicLookup { obj.SetGroupVersionKind(a.gvk)
apply = apply.WithStrictCaching()
}
if !a.opts.AllowCrossNamespace && !a.opts.AllowClusterScoped { return nil, generic.ConfigureApplyForObject(a.apply, obj, &a.opts).
apply = apply.WithSetOwnerReference(true, false). WithOwner(obj).
WithDefaultNamespace(obj.GetNamespace()). WithSetID(a.name).
WithListerNamespace(obj.GetNamespace()) ApplyObjects()
} }
if !a.opts.AllowClusterScoped { func (a *namespaceGeneratingHandler) Handle(obj *v1.Namespace, status v1.NamespaceStatus) (v1.NamespaceStatus, error) {
apply = apply.WithRestrictClusterScoped() objs, newStatus, err := a.NamespaceGeneratingHandler(obj, status)
if err != nil {
return newStatus, err
} }
return newStatus, apply. return newStatus, generic.ConfigureApplyForObject(a.apply, obj, &a.opts).
WithOwner(obj). WithOwner(obj).
WithSetID(a.name). WithSetID(a.name).
ApplyObjects(objs...) ApplyObjects(objs...)
......
...@@ -25,6 +25,7 @@ import ( ...@@ -25,6 +25,7 @@ import (
"github.com/rancher/wrangler/pkg/apply" "github.com/rancher/wrangler/pkg/apply"
"github.com/rancher/wrangler/pkg/condition" "github.com/rancher/wrangler/pkg/condition"
"github.com/rancher/wrangler/pkg/generic" "github.com/rancher/wrangler/pkg/generic"
"github.com/rancher/wrangler/pkg/kv"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
...@@ -267,6 +268,7 @@ func RegisterNodeGeneratingHandler(ctx context.Context, controller NodeControlle ...@@ -267,6 +268,7 @@ func RegisterNodeGeneratingHandler(ctx context.Context, controller NodeControlle
if opts != nil { if opts != nil {
statusHandler.opts = *opts statusHandler.opts = *opts
} }
controller.OnChange(ctx, name, statusHandler.Remove)
RegisterNodeStatusHandler(ctx, controller, condition, name, statusHandler.Handle) RegisterNodeStatusHandler(ctx, controller, condition, name, statusHandler.Handle)
} }
...@@ -281,7 +283,7 @@ func (a *nodeStatusHandler) sync(key string, obj *v1.Node) (*v1.Node, error) { ...@@ -281,7 +283,7 @@ func (a *nodeStatusHandler) sync(key string, obj *v1.Node) (*v1.Node, error) {
return obj, nil return obj, nil
} }
origStatus := obj.Status origStatus := obj.Status.DeepCopy()
obj = obj.DeepCopy() obj = obj.DeepCopy()
newStatus, err := a.handler(obj, obj.Status) newStatus, err := a.handler(obj, obj.Status)
if err != nil { if err != nil {
...@@ -289,16 +291,16 @@ func (a *nodeStatusHandler) sync(key string, obj *v1.Node) (*v1.Node, error) { ...@@ -289,16 +291,16 @@ func (a *nodeStatusHandler) sync(key string, obj *v1.Node) (*v1.Node, error) {
newStatus = *origStatus.DeepCopy() newStatus = *origStatus.DeepCopy()
} }
obj.Status = newStatus
if a.condition != "" { if a.condition != "" {
if errors.IsConflict(err) { if errors.IsConflict(err) {
a.condition.SetError(obj, "", nil) a.condition.SetError(&newStatus, "", nil)
} else { } else {
a.condition.SetError(obj, "", err) a.condition.SetError(&newStatus, "", err)
} }
} }
if !equality.Semantic.DeepEqual(origStatus, obj.Status) { if !equality.Semantic.DeepEqual(origStatus, &newStatus) {
var newErr error var newErr error
obj.Status = newStatus
obj, newErr = a.client.UpdateStatus(obj) obj, newErr = a.client.UpdateStatus(obj)
if err == nil { if err == nil {
err = newErr err = newErr
...@@ -315,29 +317,28 @@ type nodeGeneratingHandler struct { ...@@ -315,29 +317,28 @@ type nodeGeneratingHandler struct {
name string name string
} }
func (a *nodeGeneratingHandler) Handle(obj *v1.Node, status v1.NodeStatus) (v1.NodeStatus, error) { func (a *nodeGeneratingHandler) Remove(key string, obj *v1.Node) (*v1.Node, error) {
objs, newStatus, err := a.NodeGeneratingHandler(obj, status) if obj != nil {
if err != nil { return obj, nil
return newStatus, err
} }
apply := a.apply obj = &v1.Node{}
obj.Namespace, obj.Name = kv.RSplit(key, "/")
if !a.opts.DynamicLookup { obj.SetGroupVersionKind(a.gvk)
apply = apply.WithStrictCaching()
}
if !a.opts.AllowCrossNamespace && !a.opts.AllowClusterScoped { return nil, generic.ConfigureApplyForObject(a.apply, obj, &a.opts).
apply = apply.WithSetOwnerReference(true, false). WithOwner(obj).
WithDefaultNamespace(obj.GetNamespace()). WithSetID(a.name).
WithListerNamespace(obj.GetNamespace()) ApplyObjects()
} }
if !a.opts.AllowClusterScoped { func (a *nodeGeneratingHandler) Handle(obj *v1.Node, status v1.NodeStatus) (v1.NodeStatus, error) {
apply = apply.WithRestrictClusterScoped() objs, newStatus, err := a.NodeGeneratingHandler(obj, status)
if err != nil {
return newStatus, err
} }
return newStatus, apply. return newStatus, generic.ConfigureApplyForObject(a.apply, obj, &a.opts).
WithOwner(obj). WithOwner(obj).
WithSetID(a.name). WithSetID(a.name).
ApplyObjects(objs...) ApplyObjects(objs...)
......
...@@ -25,6 +25,7 @@ import ( ...@@ -25,6 +25,7 @@ import (
"github.com/rancher/wrangler/pkg/apply" "github.com/rancher/wrangler/pkg/apply"
"github.com/rancher/wrangler/pkg/condition" "github.com/rancher/wrangler/pkg/condition"
"github.com/rancher/wrangler/pkg/generic" "github.com/rancher/wrangler/pkg/generic"
"github.com/rancher/wrangler/pkg/kv"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
...@@ -267,6 +268,7 @@ func RegisterPersistentVolumeClaimGeneratingHandler(ctx context.Context, control ...@@ -267,6 +268,7 @@ func RegisterPersistentVolumeClaimGeneratingHandler(ctx context.Context, control
if opts != nil { if opts != nil {
statusHandler.opts = *opts statusHandler.opts = *opts
} }
controller.OnChange(ctx, name, statusHandler.Remove)
RegisterPersistentVolumeClaimStatusHandler(ctx, controller, condition, name, statusHandler.Handle) RegisterPersistentVolumeClaimStatusHandler(ctx, controller, condition, name, statusHandler.Handle)
} }
...@@ -281,7 +283,7 @@ func (a *persistentVolumeClaimStatusHandler) sync(key string, obj *v1.Persistent ...@@ -281,7 +283,7 @@ func (a *persistentVolumeClaimStatusHandler) sync(key string, obj *v1.Persistent
return obj, nil return obj, nil
} }
origStatus := obj.Status origStatus := obj.Status.DeepCopy()
obj = obj.DeepCopy() obj = obj.DeepCopy()
newStatus, err := a.handler(obj, obj.Status) newStatus, err := a.handler(obj, obj.Status)
if err != nil { if err != nil {
...@@ -289,16 +291,16 @@ func (a *persistentVolumeClaimStatusHandler) sync(key string, obj *v1.Persistent ...@@ -289,16 +291,16 @@ func (a *persistentVolumeClaimStatusHandler) sync(key string, obj *v1.Persistent
newStatus = *origStatus.DeepCopy() newStatus = *origStatus.DeepCopy()
} }
obj.Status = newStatus
if a.condition != "" { if a.condition != "" {
if errors.IsConflict(err) { if errors.IsConflict(err) {
a.condition.SetError(obj, "", nil) a.condition.SetError(&newStatus, "", nil)
} else { } else {
a.condition.SetError(obj, "", err) a.condition.SetError(&newStatus, "", err)
} }
} }
if !equality.Semantic.DeepEqual(origStatus, obj.Status) { if !equality.Semantic.DeepEqual(origStatus, &newStatus) {
var newErr error var newErr error
obj.Status = newStatus
obj, newErr = a.client.UpdateStatus(obj) obj, newErr = a.client.UpdateStatus(obj)
if err == nil { if err == nil {
err = newErr err = newErr
...@@ -315,29 +317,28 @@ type persistentVolumeClaimGeneratingHandler struct { ...@@ -315,29 +317,28 @@ type persistentVolumeClaimGeneratingHandler struct {
name string name string
} }
func (a *persistentVolumeClaimGeneratingHandler) Handle(obj *v1.PersistentVolumeClaim, status v1.PersistentVolumeClaimStatus) (v1.PersistentVolumeClaimStatus, error) { func (a *persistentVolumeClaimGeneratingHandler) Remove(key string, obj *v1.PersistentVolumeClaim) (*v1.PersistentVolumeClaim, error) {
objs, newStatus, err := a.PersistentVolumeClaimGeneratingHandler(obj, status) if obj != nil {
if err != nil { return obj, nil
return newStatus, err
} }
apply := a.apply obj = &v1.PersistentVolumeClaim{}
obj.Namespace, obj.Name = kv.RSplit(key, "/")
if !a.opts.DynamicLookup { obj.SetGroupVersionKind(a.gvk)
apply = apply.WithStrictCaching()
}
if !a.opts.AllowCrossNamespace && !a.opts.AllowClusterScoped { return nil, generic.ConfigureApplyForObject(a.apply, obj, &a.opts).
apply = apply.WithSetOwnerReference(true, false). WithOwner(obj).
WithDefaultNamespace(obj.GetNamespace()). WithSetID(a.name).
WithListerNamespace(obj.GetNamespace()) ApplyObjects()
} }
if !a.opts.AllowClusterScoped { func (a *persistentVolumeClaimGeneratingHandler) Handle(obj *v1.PersistentVolumeClaim, status v1.PersistentVolumeClaimStatus) (v1.PersistentVolumeClaimStatus, error) {
apply = apply.WithRestrictClusterScoped() objs, newStatus, err := a.PersistentVolumeClaimGeneratingHandler(obj, status)
if err != nil {
return newStatus, err
} }
return newStatus, apply. return newStatus, generic.ConfigureApplyForObject(a.apply, obj, &a.opts).
WithOwner(obj). WithOwner(obj).
WithSetID(a.name). WithSetID(a.name).
ApplyObjects(objs...) ApplyObjects(objs...)
......
...@@ -25,6 +25,7 @@ import ( ...@@ -25,6 +25,7 @@ import (
"github.com/rancher/wrangler/pkg/apply" "github.com/rancher/wrangler/pkg/apply"
"github.com/rancher/wrangler/pkg/condition" "github.com/rancher/wrangler/pkg/condition"
"github.com/rancher/wrangler/pkg/generic" "github.com/rancher/wrangler/pkg/generic"
"github.com/rancher/wrangler/pkg/kv"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
...@@ -267,6 +268,7 @@ func RegisterPodGeneratingHandler(ctx context.Context, controller PodController, ...@@ -267,6 +268,7 @@ func RegisterPodGeneratingHandler(ctx context.Context, controller PodController,
if opts != nil { if opts != nil {
statusHandler.opts = *opts statusHandler.opts = *opts
} }
controller.OnChange(ctx, name, statusHandler.Remove)
RegisterPodStatusHandler(ctx, controller, condition, name, statusHandler.Handle) RegisterPodStatusHandler(ctx, controller, condition, name, statusHandler.Handle)
} }
...@@ -281,7 +283,7 @@ func (a *podStatusHandler) sync(key string, obj *v1.Pod) (*v1.Pod, error) { ...@@ -281,7 +283,7 @@ func (a *podStatusHandler) sync(key string, obj *v1.Pod) (*v1.Pod, error) {
return obj, nil return obj, nil
} }
origStatus := obj.Status origStatus := obj.Status.DeepCopy()
obj = obj.DeepCopy() obj = obj.DeepCopy()
newStatus, err := a.handler(obj, obj.Status) newStatus, err := a.handler(obj, obj.Status)
if err != nil { if err != nil {
...@@ -289,16 +291,16 @@ func (a *podStatusHandler) sync(key string, obj *v1.Pod) (*v1.Pod, error) { ...@@ -289,16 +291,16 @@ func (a *podStatusHandler) sync(key string, obj *v1.Pod) (*v1.Pod, error) {
newStatus = *origStatus.DeepCopy() newStatus = *origStatus.DeepCopy()
} }
obj.Status = newStatus
if a.condition != "" { if a.condition != "" {
if errors.IsConflict(err) { if errors.IsConflict(err) {
a.condition.SetError(obj, "", nil) a.condition.SetError(&newStatus, "", nil)
} else { } else {
a.condition.SetError(obj, "", err) a.condition.SetError(&newStatus, "", err)
} }
} }
if !equality.Semantic.DeepEqual(origStatus, obj.Status) { if !equality.Semantic.DeepEqual(origStatus, &newStatus) {
var newErr error var newErr error
obj.Status = newStatus
obj, newErr = a.client.UpdateStatus(obj) obj, newErr = a.client.UpdateStatus(obj)
if err == nil { if err == nil {
err = newErr err = newErr
...@@ -315,29 +317,28 @@ type podGeneratingHandler struct { ...@@ -315,29 +317,28 @@ type podGeneratingHandler struct {
name string name string
} }
func (a *podGeneratingHandler) Handle(obj *v1.Pod, status v1.PodStatus) (v1.PodStatus, error) { func (a *podGeneratingHandler) Remove(key string, obj *v1.Pod) (*v1.Pod, error) {
objs, newStatus, err := a.PodGeneratingHandler(obj, status) if obj != nil {
if err != nil { return obj, nil
return newStatus, err
} }
apply := a.apply obj = &v1.Pod{}
obj.Namespace, obj.Name = kv.RSplit(key, "/")
if !a.opts.DynamicLookup { obj.SetGroupVersionKind(a.gvk)
apply = apply.WithStrictCaching()
}
if !a.opts.AllowCrossNamespace && !a.opts.AllowClusterScoped { return nil, generic.ConfigureApplyForObject(a.apply, obj, &a.opts).
apply = apply.WithSetOwnerReference(true, false). WithOwner(obj).
WithDefaultNamespace(obj.GetNamespace()). WithSetID(a.name).
WithListerNamespace(obj.GetNamespace()) ApplyObjects()
} }
if !a.opts.AllowClusterScoped { func (a *podGeneratingHandler) Handle(obj *v1.Pod, status v1.PodStatus) (v1.PodStatus, error) {
apply = apply.WithRestrictClusterScoped() objs, newStatus, err := a.PodGeneratingHandler(obj, status)
if err != nil {
return newStatus, err
} }
return newStatus, apply. return newStatus, generic.ConfigureApplyForObject(a.apply, obj, &a.opts).
WithOwner(obj). WithOwner(obj).
WithSetID(a.name). WithSetID(a.name).
ApplyObjects(objs...) ApplyObjects(objs...)
......
...@@ -25,6 +25,7 @@ import ( ...@@ -25,6 +25,7 @@ import (
"github.com/rancher/wrangler/pkg/apply" "github.com/rancher/wrangler/pkg/apply"
"github.com/rancher/wrangler/pkg/condition" "github.com/rancher/wrangler/pkg/condition"
"github.com/rancher/wrangler/pkg/generic" "github.com/rancher/wrangler/pkg/generic"
"github.com/rancher/wrangler/pkg/kv"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
...@@ -267,6 +268,7 @@ func RegisterServiceGeneratingHandler(ctx context.Context, controller ServiceCon ...@@ -267,6 +268,7 @@ func RegisterServiceGeneratingHandler(ctx context.Context, controller ServiceCon
if opts != nil { if opts != nil {
statusHandler.opts = *opts statusHandler.opts = *opts
} }
controller.OnChange(ctx, name, statusHandler.Remove)
RegisterServiceStatusHandler(ctx, controller, condition, name, statusHandler.Handle) RegisterServiceStatusHandler(ctx, controller, condition, name, statusHandler.Handle)
} }
...@@ -281,7 +283,7 @@ func (a *serviceStatusHandler) sync(key string, obj *v1.Service) (*v1.Service, e ...@@ -281,7 +283,7 @@ func (a *serviceStatusHandler) sync(key string, obj *v1.Service) (*v1.Service, e
return obj, nil return obj, nil
} }
origStatus := obj.Status origStatus := obj.Status.DeepCopy()
obj = obj.DeepCopy() obj = obj.DeepCopy()
newStatus, err := a.handler(obj, obj.Status) newStatus, err := a.handler(obj, obj.Status)
if err != nil { if err != nil {
...@@ -289,16 +291,16 @@ func (a *serviceStatusHandler) sync(key string, obj *v1.Service) (*v1.Service, e ...@@ -289,16 +291,16 @@ func (a *serviceStatusHandler) sync(key string, obj *v1.Service) (*v1.Service, e
newStatus = *origStatus.DeepCopy() newStatus = *origStatus.DeepCopy()
} }
obj.Status = newStatus
if a.condition != "" { if a.condition != "" {
if errors.IsConflict(err) { if errors.IsConflict(err) {
a.condition.SetError(obj, "", nil) a.condition.SetError(&newStatus, "", nil)
} else { } else {
a.condition.SetError(obj, "", err) a.condition.SetError(&newStatus, "", err)
} }
} }
if !equality.Semantic.DeepEqual(origStatus, obj.Status) { if !equality.Semantic.DeepEqual(origStatus, &newStatus) {
var newErr error var newErr error
obj.Status = newStatus
obj, newErr = a.client.UpdateStatus(obj) obj, newErr = a.client.UpdateStatus(obj)
if err == nil { if err == nil {
err = newErr err = newErr
...@@ -315,29 +317,28 @@ type serviceGeneratingHandler struct { ...@@ -315,29 +317,28 @@ type serviceGeneratingHandler struct {
name string name string
} }
func (a *serviceGeneratingHandler) Handle(obj *v1.Service, status v1.ServiceStatus) (v1.ServiceStatus, error) { func (a *serviceGeneratingHandler) Remove(key string, obj *v1.Service) (*v1.Service, error) {
objs, newStatus, err := a.ServiceGeneratingHandler(obj, status) if obj != nil {
if err != nil { return obj, nil
return newStatus, err
} }
apply := a.apply obj = &v1.Service{}
obj.Namespace, obj.Name = kv.RSplit(key, "/")
if !a.opts.DynamicLookup { obj.SetGroupVersionKind(a.gvk)
apply = apply.WithStrictCaching()
}
if !a.opts.AllowCrossNamespace && !a.opts.AllowClusterScoped { return nil, generic.ConfigureApplyForObject(a.apply, obj, &a.opts).
apply = apply.WithSetOwnerReference(true, false). WithOwner(obj).
WithDefaultNamespace(obj.GetNamespace()). WithSetID(a.name).
WithListerNamespace(obj.GetNamespace()) ApplyObjects()
} }
if !a.opts.AllowClusterScoped { func (a *serviceGeneratingHandler) Handle(obj *v1.Service, status v1.ServiceStatus) (v1.ServiceStatus, error) {
apply = apply.WithRestrictClusterScoped() objs, newStatus, err := a.ServiceGeneratingHandler(obj, status)
if err != nil {
return newStatus, err
} }
return newStatus, apply. return newStatus, generic.ConfigureApplyForObject(a.apply, obj, &a.opts).
WithOwner(obj). WithOwner(obj).
WithSetID(a.name). WithSetID(a.name).
ApplyObjects(objs...) ApplyObjects(objs...)
......
...@@ -52,18 +52,23 @@ func NewFactoryFromConfigOrDie(config *rest.Config) *Factory { ...@@ -52,18 +52,23 @@ func NewFactoryFromConfigOrDie(config *rest.Config) *Factory {
} }
func NewFactoryFromConfig(config *rest.Config) (*Factory, error) { func NewFactoryFromConfig(config *rest.Config) (*Factory, error) {
cs, err := clientset.NewForConfig(config) return NewFactoryFromConfigWithOptions(config, nil)
if err != nil {
return nil, err
}
informerFactory := informers.NewSharedInformerFactory(cs, 2*time.Hour)
return NewFactory(cs, informerFactory), nil
} }
func NewFactoryFromConfigWithNamespace(config *rest.Config, namespace string) (*Factory, error) { func NewFactoryFromConfigWithNamespace(config *rest.Config, namespace string) (*Factory, error) {
if namespace == "" { return NewFactoryFromConfigWithOptions(config, &FactoryOptions{
return NewFactoryFromConfig(config) Namespace: namespace,
})
}
type FactoryOptions struct {
Namespace string
Resync time.Duration
}
func NewFactoryFromConfigWithOptions(config *rest.Config, opts *FactoryOptions) (*Factory, error) {
if opts == nil {
opts = &FactoryOptions{}
} }
cs, err := clientset.NewForConfig(config) cs, err := clientset.NewForConfig(config)
...@@ -71,7 +76,17 @@ func NewFactoryFromConfigWithNamespace(config *rest.Config, namespace string) (* ...@@ -71,7 +76,17 @@ func NewFactoryFromConfigWithNamespace(config *rest.Config, namespace string) (*
return nil, err return nil, err
} }
informerFactory := informers.NewSharedInformerFactoryWithOptions(cs, 2*time.Hour, informers.WithNamespace(namespace)) resync := opts.Resync
if resync == 0 {
resync = 2 * time.Hour
}
if opts.Namespace == "" {
informerFactory := informers.NewSharedInformerFactory(cs, resync)
return NewFactory(cs, informerFactory), nil
}
informerFactory := informers.NewSharedInformerFactoryWithOptions(cs, resync, informers.WithNamespace(opts.Namespace))
return NewFactory(cs, informerFactory), nil return NewFactory(cs, informerFactory), nil
} }
......
...@@ -28,18 +28,45 @@ type Reconciler func(oldObj runtime.Object, newObj runtime.Object) (bool, error) ...@@ -28,18 +28,45 @@ type Reconciler func(oldObj runtime.Object, newObj runtime.Object) (bool, error)
type ClientFactory func(gvr schema.GroupVersionResource) (dynamic.NamespaceableResourceInterface, error) type ClientFactory func(gvr schema.GroupVersionResource) (dynamic.NamespaceableResourceInterface, error)
type InformerFactory interface {
Get(gvk schema.GroupVersionKind, gvr schema.GroupVersionResource) (cache.SharedIndexInformer, error)
}
type InformerGetter interface { type InformerGetter interface {
Informer() cache.SharedIndexInformer Informer() cache.SharedIndexInformer
GroupVersionKind() schema.GroupVersionKind GroupVersionKind() schema.GroupVersionKind
} }
type PatchByGVK map[schema.GroupVersionKind]map[objectset.ObjectKey]string
func (p PatchByGVK) Add(gvk schema.GroupVersionKind, namespace, name, patch string) {
d, ok := p[gvk]
if !ok {
d = map[objectset.ObjectKey]string{}
p[gvk] = d
}
d[objectset.ObjectKey{
Name: name,
Namespace: namespace,
}] = patch
}
type Plan struct {
Create objectset.ObjectKeyByGVK
Delete objectset.ObjectKeyByGVK
Update PatchByGVK
Objects []runtime.Object
}
type Apply interface { type Apply interface {
Apply(set *objectset.ObjectSet) error Apply(set *objectset.ObjectSet) error
ApplyObjects(objs ...runtime.Object) error ApplyObjects(objs ...runtime.Object) error
WithContext(ctx context.Context) Apply WithContext(ctx context.Context) Apply
WithCacheTypes(igs ...InformerGetter) Apply WithCacheTypes(igs ...InformerGetter) Apply
WithCacheTypeFactory(factory InformerFactory) Apply
WithSetID(id string) Apply WithSetID(id string) Apply
WithOwner(obj runtime.Object) Apply WithOwner(obj runtime.Object) Apply
WithOwnerKey(key string, gvk schema.GroupVersionKind) Apply
WithInjector(injs ...injectors.ConfigInjector) Apply WithInjector(injs ...injectors.ConfigInjector) Apply
WithInjectorName(injs ...string) Apply WithInjectorName(injs ...string) Apply
WithPatcher(gvk schema.GroupVersionKind, patchers Patcher) Apply WithPatcher(gvk schema.GroupVersionKind, patchers Patcher) Apply
...@@ -53,6 +80,10 @@ type Apply interface { ...@@ -53,6 +80,10 @@ type Apply interface {
WithNoDelete() Apply WithNoDelete() Apply
WithGVK(gvks ...schema.GroupVersionKind) Apply WithGVK(gvks ...schema.GroupVersionKind) Apply
WithSetOwnerReference(controller, block bool) Apply WithSetOwnerReference(controller, block bool) Apply
FindOwner(obj runtime.Object) (runtime.Object, error)
PurgeOrphan(obj runtime.Object) error
DryRun(objs ...runtime.Object) (Plan, error)
} }
func NewForConfig(cfg *rest.Config) (Apply, error) { func NewForConfig(cfg *rest.Config) (Apply, error) {
...@@ -70,6 +101,7 @@ func New(discovery discovery.DiscoveryInterface, cf ClientFactory, igs ...Inform ...@@ -70,6 +101,7 @@ func New(discovery discovery.DiscoveryInterface, cf ClientFactory, igs ...Inform
clientFactory: cf, clientFactory: cf,
discovery: discovery, discovery: discovery,
namespaced: map[schema.GroupVersionKind]bool{}, namespaced: map[schema.GroupVersionKind]bool{},
gvkToGVR: map[schema.GroupVersionKind]schema.GroupVersionResource{},
clients: map[schema.GroupVersionKind]dynamic.NamespaceableResourceInterface{}, clients: map[schema.GroupVersionKind]dynamic.NamespaceableResourceInterface{},
}, },
informers: map[schema.GroupVersionKind]cache.SharedIndexInformer{}, informers: map[schema.GroupVersionKind]cache.SharedIndexInformer{},
...@@ -93,6 +125,7 @@ type clients struct { ...@@ -93,6 +125,7 @@ type clients struct {
clientFactory ClientFactory clientFactory ClientFactory
discovery discovery.DiscoveryInterface discovery discovery.DiscoveryInterface
namespaced map[schema.GroupVersionKind]bool namespaced map[schema.GroupVersionKind]bool
gvkToGVR map[schema.GroupVersionKind]schema.GroupVersionResource
clients map[schema.GroupVersionKind]dynamic.NamespaceableResourceInterface clients map[schema.GroupVersionKind]dynamic.NamespaceableResourceInterface
} }
...@@ -102,6 +135,12 @@ func (c *clients) IsNamespaced(gvk schema.GroupVersionKind) bool { ...@@ -102,6 +135,12 @@ func (c *clients) IsNamespaced(gvk schema.GroupVersionKind) bool {
return c.namespaced[gvk] return c.namespaced[gvk]
} }
func (c *clients) gvr(gvk schema.GroupVersionKind) schema.GroupVersionResource {
c.Lock()
defer c.Unlock()
return c.gvkToGVR[gvk]
}
func (c *clients) client(gvk schema.GroupVersionKind) (dynamic.NamespaceableResourceInterface, error) { func (c *clients) client(gvk schema.GroupVersionKind) (dynamic.NamespaceableResourceInterface, error) {
c.Lock() c.Lock()
defer c.Unlock() defer c.Unlock()
...@@ -127,6 +166,7 @@ func (c *clients) client(gvk schema.GroupVersionKind) (dynamic.NamespaceableReso ...@@ -127,6 +166,7 @@ func (c *clients) client(gvk schema.GroupVersionKind) (dynamic.NamespaceableReso
c.namespaced[gvk] = resource.Namespaced c.namespaced[gvk] = resource.Namespaced
c.clients[gvk] = client c.clients[gvk] = client
c.gvkToGVR[gvk] = gvk.GroupVersion().WithResource(resource.Name)
return client, nil return client, nil
} }
...@@ -144,6 +184,10 @@ func (a *apply) newDesiredSet() desiredSet { ...@@ -144,6 +184,10 @@ func (a *apply) newDesiredSet() desiredSet {
} }
} }
func (a *apply) DryRun(objs ...runtime.Object) (Plan, error) {
return a.newDesiredSet().DryRun(objs...)
}
func (a *apply) Apply(set *objectset.ObjectSet) error { func (a *apply) Apply(set *objectset.ObjectSet) error {
return a.newDesiredSet().Apply(set) return a.newDesiredSet().Apply(set)
} }
...@@ -162,6 +206,10 @@ func (a *apply) WithOwner(obj runtime.Object) Apply { ...@@ -162,6 +206,10 @@ func (a *apply) WithOwner(obj runtime.Object) Apply {
return a.newDesiredSet().WithOwner(obj) return a.newDesiredSet().WithOwner(obj)
} }
func (a *apply) WithOwnerKey(key string, gvk schema.GroupVersionKind) Apply {
return a.newDesiredSet().WithOwnerKey(key, gvk)
}
func (a *apply) WithInjector(injs ...injectors.ConfigInjector) Apply { func (a *apply) WithInjector(injs ...injectors.ConfigInjector) Apply {
return a.newDesiredSet().WithInjector(injs...) return a.newDesiredSet().WithInjector(injs...)
} }
...@@ -174,6 +222,10 @@ func (a *apply) WithCacheTypes(igs ...InformerGetter) Apply { ...@@ -174,6 +222,10 @@ func (a *apply) WithCacheTypes(igs ...InformerGetter) Apply {
return a.newDesiredSet().WithCacheTypes(igs...) return a.newDesiredSet().WithCacheTypes(igs...)
} }
func (a *apply) WithCacheTypeFactory(factory InformerFactory) Apply {
return a.newDesiredSet().WithCacheTypeFactory(factory)
}
func (a *apply) WithGVK(gvks ...schema.GroupVersionKind) Apply { func (a *apply) WithGVK(gvks ...schema.GroupVersionKind) Apply {
return a.newDesiredSet().WithGVK(gvks...) return a.newDesiredSet().WithGVK(gvks...)
} }
...@@ -221,3 +273,11 @@ func (a *apply) WithSetOwnerReference(controller, block bool) Apply { ...@@ -221,3 +273,11 @@ func (a *apply) WithSetOwnerReference(controller, block bool) Apply {
func (a *apply) WithContext(ctx context.Context) Apply { func (a *apply) WithContext(ctx context.Context) Apply {
return a.newDesiredSet().WithContext(ctx) return a.newDesiredSet().WithContext(ctx)
} }
func (a *apply) FindOwner(obj runtime.Object) (runtime.Object, error) {
return a.newDesiredSet().FindOwner(obj)
}
func (a *apply) PurgeOrphan(obj runtime.Object) error {
return a.newDesiredSet().PurgeOrphan(obj)
}
...@@ -3,8 +3,10 @@ package apply ...@@ -3,8 +3,10 @@ package apply
import ( import (
"context" "context"
"github.com/rancher/wrangler/pkg/apply/injectors" "github.com/rancher/wrangler/pkg/apply/injectors"
"github.com/rancher/wrangler/pkg/kv"
"github.com/rancher/wrangler/pkg/merr" "github.com/rancher/wrangler/pkg/merr"
"github.com/rancher/wrangler/pkg/objectset" "github.com/rancher/wrangler/pkg/objectset"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/cache"
...@@ -12,7 +14,7 @@ import ( ...@@ -12,7 +14,7 @@ import (
type desiredSet struct { type desiredSet struct {
a *apply a *apply
ctx context.Context ctx context.Context
defaultNamespace string defaultNamespace string
listerNamespace string listerNamespace string
setOwnerReference bool setOwnerReference bool
...@@ -23,6 +25,7 @@ type desiredSet struct { ...@@ -23,6 +25,7 @@ type desiredSet struct {
pruneTypes map[schema.GroupVersionKind]cache.SharedIndexInformer pruneTypes map[schema.GroupVersionKind]cache.SharedIndexInformer
patchers map[schema.GroupVersionKind]Patcher patchers map[schema.GroupVersionKind]Patcher
reconcilers map[schema.GroupVersionKind]Reconciler reconcilers map[schema.GroupVersionKind]Reconciler
informerFactory InformerFactory
remove bool remove bool
noDelete bool noDelete bool
setID string setID string
...@@ -33,6 +36,9 @@ type desiredSet struct { ...@@ -33,6 +36,9 @@ type desiredSet struct {
ratelimitingQps float32 ratelimitingQps float32
injectorNames []string injectorNames []string
errs []error errs []error
createPlan bool
plan Plan
} }
func (o *desiredSet) err(err error) error { func (o *desiredSet) err(err error) error {
...@@ -44,6 +50,12 @@ func (o desiredSet) Err() error { ...@@ -44,6 +50,12 @@ func (o desiredSet) Err() error {
return merr.NewErrors(append(o.errs, o.objs.Err())...) return merr.NewErrors(append(o.errs, o.objs.Err())...)
} }
func (o desiredSet) DryRun(objs ...runtime.Object) (Plan, error) {
o.objs = objectset.NewObjectSet()
o.objs.Add(objs...)
return o.dryRun()
}
func (o desiredSet) Apply(set *objectset.ObjectSet) error { func (o desiredSet) Apply(set *objectset.ObjectSet) error {
if set == nil { if set == nil {
set = objectset.NewObjectSet() set = objectset.NewObjectSet()
...@@ -76,6 +88,14 @@ func (o desiredSet) WithSetID(id string) Apply { ...@@ -76,6 +88,14 @@ func (o desiredSet) WithSetID(id string) Apply {
return o return o
} }
func (o desiredSet) WithOwnerKey(key string, gvk schema.GroupVersionKind) Apply {
obj := &v1.PartialObjectMetadata{}
obj.Namespace, obj.Name = kv.RSplit(key, "/")
obj.SetGroupVersionKind(gvk)
o.owner = obj
return o
}
func (o desiredSet) WithOwner(obj runtime.Object) Apply { func (o desiredSet) WithOwner(obj runtime.Object) Apply {
o.owner = obj o.owner = obj
return o return o
...@@ -98,6 +118,11 @@ func (o desiredSet) WithInjectorName(injs ...string) Apply { ...@@ -98,6 +118,11 @@ func (o desiredSet) WithInjectorName(injs ...string) Apply {
return o return o
} }
func (o desiredSet) WithCacheTypeFactory(factory InformerFactory) Apply {
o.informerFactory = factory
return o
}
func (o desiredSet) WithCacheTypes(igs ...InformerGetter) Apply { func (o desiredSet) WithCacheTypes(igs ...InformerGetter) Apply {
pruneTypes := make(map[schema.GroupVersionKind]cache.SharedIndexInformer, len(igs)) pruneTypes := make(map[schema.GroupVersionKind]cache.SharedIndexInformer, len(igs))
for k, v := range o.pruneTypes { for k, v := range o.pruneTypes {
...@@ -147,7 +172,11 @@ func (o desiredSet) WithRestrictClusterScoped() Apply { ...@@ -147,7 +172,11 @@ func (o desiredSet) WithRestrictClusterScoped() Apply {
} }
func (o desiredSet) WithDefaultNamespace(ns string) Apply { func (o desiredSet) WithDefaultNamespace(ns string) Apply {
o.defaultNamespace = ns if ns == "" {
o.defaultNamespace = defaultNamespace
} else {
o.defaultNamespace = ns
}
return o return o
} }
......
...@@ -27,6 +27,7 @@ const ( ...@@ -27,6 +27,7 @@ const (
LabelName = "objectset.rio.cattle.io/owner-name" LabelName = "objectset.rio.cattle.io/owner-name"
LabelNamespace = "objectset.rio.cattle.io/owner-namespace" LabelNamespace = "objectset.rio.cattle.io/owner-namespace"
LabelHash = "objectset.rio.cattle.io/hash" LabelHash = "objectset.rio.cattle.io/hash"
LabelPrefix = "objectset.rio.cattle.io/"
) )
var ( var (
...@@ -58,6 +59,15 @@ func (o *desiredSet) getRateLimit(labelHash string) flowcontrol.RateLimiter { ...@@ -58,6 +59,15 @@ func (o *desiredSet) getRateLimit(labelHash string) flowcontrol.RateLimiter {
return rl return rl
} }
func (o *desiredSet) dryRun() (Plan, error) {
o.createPlan = true
o.plan.Create = objectset.ObjectKeyByGVK{}
o.plan.Update = PatchByGVK{}
o.plan.Delete = objectset.ObjectKeyByGVK{}
err := o.apply()
return o.plan, err
}
func (o *desiredSet) apply() error { func (o *desiredSet) apply() error {
if o.objs == nil || o.objs.Len() == 0 { if o.objs == nil || o.objs.Len() == 0 {
o.remove = true o.remove = true
...@@ -67,7 +77,7 @@ func (o *desiredSet) apply() error { ...@@ -67,7 +77,7 @@ func (o *desiredSet) apply() error {
return err return err
} }
labelSet, annotationSet, err := o.getLabelsAndAnnotations() labelSet, annotationSet, err := GetLabelsAndAnnotations(o.setID, o.owner)
if err != nil { if err != nil {
return o.err(err) return o.err(err)
} }
...@@ -90,13 +100,13 @@ func (o *desiredSet) apply() error { ...@@ -90,13 +100,13 @@ func (o *desiredSet) apply() error {
objs := o.collect(objList) objs := o.collect(objList)
debugID := o.debugID() debugID := o.debugID()
req, err := labels.NewRequirement(LabelHash, selection.Equals, []string{labelSet[LabelHash]}) sel, err := GetSelector(labelSet)
if err != nil { if err != nil {
return o.err(err) return o.err(err)
} }
for _, gvk := range o.objs.GVKOrder(o.knownGVK()...) { for _, gvk := range o.objs.GVKOrder(o.knownGVK()...) {
o.process(debugID, labels.NewSelector().Add(*req), gvk, objs[gvk]) o.process(debugID, sel, gvk, objs[gvk])
} }
return o.Err() return o.Err()
...@@ -161,18 +171,26 @@ func (o *desiredSet) runInjectors(objList []runtime.Object) ([]runtime.Object, e ...@@ -161,18 +171,26 @@ func (o *desiredSet) runInjectors(objList []runtime.Object) ([]runtime.Object, e
return objList, nil return objList, nil
} }
func (o *desiredSet) getLabelsAndAnnotations() (map[string]string, map[string]string, error) { func GetSelector(labelSet map[string]string) (labels.Selector, error) {
req, err := labels.NewRequirement(LabelHash, selection.Equals, []string{labelSet[LabelHash]})
if err != nil {
return nil, err
}
return labels.NewSelector().Add(*req), nil
}
func GetLabelsAndAnnotations(setID string, owner runtime.Object) (map[string]string, map[string]string, error) {
annotations := map[string]string{ annotations := map[string]string{
LabelID: o.setID, LabelID: setID,
} }
if o.owner != nil { if owner != nil {
gvk, err := gvk2.Get(o.owner) gvk, err := gvk2.Get(owner)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
annotations[LabelGVK] = gvk.String() annotations[LabelGVK] = gvk.String()
metadata, err := meta.Accessor(o.owner) metadata, err := meta.Accessor(owner)
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("failed to get metadata for %s", gvk) return nil, nil, fmt.Errorf("failed to get metadata for %s", gvk)
} }
......
...@@ -5,6 +5,9 @@ import ( ...@@ -5,6 +5,9 @@ import (
"compress/gzip" "compress/gzip"
"encoding/base64" "encoding/base64"
"io/ioutil" "io/ioutil"
"strings"
data2 "github.com/rancher/wrangler/pkg/data"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/rancher/wrangler/pkg/data/convert" "github.com/rancher/wrangler/pkg/data/convert"
...@@ -95,7 +98,7 @@ func emptyMaps(data map[string]interface{}, keys ...string) bool { ...@@ -95,7 +98,7 @@ func emptyMaps(data map[string]interface{}, keys ...string) bool {
return true return true
} }
func sanitizePatch(patch []byte) ([]byte, error) { func sanitizePatch(patch []byte, removeObjectSetAnnotation bool) ([]byte, error) {
mod := false mod := false
data := map[string]interface{}{} data := map[string]interface{}{}
err := json.Unmarshal(patch, &data) err := json.Unmarshal(patch, &data)
...@@ -117,6 +120,23 @@ func sanitizePatch(patch []byte) ([]byte, error) { ...@@ -117,6 +120,23 @@ func sanitizePatch(patch []byte) ([]byte, error) {
mod = true mod = true
} }
if removeObjectSetAnnotation {
metadata := convert.ToMapInterface(data2.GetValueN(data, "metadata"))
annotations := convert.ToMapInterface(data2.GetValueN(data, "metadata", "annotations"))
for k := range annotations {
if strings.HasPrefix(k, LabelPrefix) {
mod = true
delete(annotations, k)
}
}
if mod && len(annotations) == 0 {
delete(metadata, "annotations")
if len(metadata) == 0 {
delete(data, "metadata")
}
}
}
if emptyMaps(data, "metadata", "annotations") { if emptyMaps(data, "metadata", "annotations") {
return []byte("{}"), nil return []byte("{}"), nil
} }
...@@ -152,7 +172,7 @@ func applyPatch(gvk schema.GroupVersionKind, reconciler Reconciler, patcher Patc ...@@ -152,7 +172,7 @@ func applyPatch(gvk schema.GroupVersionKind, reconciler Reconciler, patcher Patc
return false, nil return false, nil
} }
patch, err = sanitizePatch(patch) patch, err = sanitizePatch(patch, false)
if err != nil { if err != nil {
return false, err return false, err
} }
...@@ -172,6 +192,9 @@ func applyPatch(gvk schema.GroupVersionKind, reconciler Reconciler, patcher Patc ...@@ -172,6 +192,9 @@ func applyPatch(gvk schema.GroupVersionKind, reconciler Reconciler, patcher Patc
if err != nil { if err != nil {
return false, err return false, err
} }
if originalObject == nil {
originalObject = oldObject
}
handled, err := reconciler(originalObject, newObject) handled, err := reconciler(originalObject, newObject)
if err != nil { if err != nil {
return false, err return false, err
...@@ -187,13 +210,17 @@ func applyPatch(gvk schema.GroupVersionKind, reconciler Reconciler, patcher Patc ...@@ -187,13 +210,17 @@ func applyPatch(gvk schema.GroupVersionKind, reconciler Reconciler, patcher Patc
return true, err return true, err
} }
func (o *desiredSet) compareObjects(gvk schema.GroupVersionKind, patcher Patcher, client dynamic.NamespaceableResourceInterface, debugID string, oldObject, newObject runtime.Object, force bool) error { func (o *desiredSet) compareObjects(gvk schema.GroupVersionKind, reconciler Reconciler, patcher Patcher, client dynamic.NamespaceableResourceInterface, debugID string, oldObject, newObject runtime.Object, force bool) error {
oldMetadata, err := meta.Accessor(oldObject) oldMetadata, err := meta.Accessor(oldObject)
if err != nil { if err != nil {
return err return err
} }
if ran, err := applyPatch(gvk, o.reconcilers[gvk], patcher, debugID, oldObject, newObject); err != nil { if o.createPlan {
o.plan.Objects = append(o.plan.Objects, oldObject)
}
if ran, err := applyPatch(gvk, reconciler, patcher, debugID, oldObject, newObject); err != nil {
return err return err
} else if !ran { } else if !ran {
logrus.Debugf("DesiredSet - No change(2) %s %s/%s for %s", gvk, oldMetadata.GetNamespace(), oldMetadata.GetName(), debugID) logrus.Debugf("DesiredSet - No change(2) %s %s/%s for %s", gvk, oldMetadata.GetNamespace(), oldMetadata.GetName(), debugID)
......
package apply
import (
"fmt"
"strings"
"github.com/rancher/wrangler/pkg/gvk"
"github.com/rancher/wrangler/pkg/kv"
"github.com/pkg/errors"
namer "github.com/rancher/wrangler/pkg/name"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/tools/cache"
)
var (
ErrOwnerNotFound = errors.New("owner not found")
)
func notFound(name string, gvk schema.GroupVersionKind) error {
// this is not proper, but does it really matter that much? If you find this
// line while researching a bug, then the answer is probably yes.
resource := namer.GuessPluralName(strings.ToLower(gvk.Kind))
return apierrors.NewNotFound(schema.GroupResource{
Group: gvk.Group,
Resource: resource,
}, name)
}
func getGVK(gvkLabel string, gvk *schema.GroupVersionKind) error {
parts := strings.Split(gvkLabel, ", Kind=")
if len(parts) != 2 {
return fmt.Errorf("invalid GVK format: %s", gvkLabel)
}
gvk.Group, gvk.Version = kv.Split(parts[0], "/")
gvk.Kind = parts[1]
return nil
}
func (o desiredSet) FindOwner(obj runtime.Object) (runtime.Object, error) {
if obj == nil {
return nil, ErrOwnerNotFound
}
meta, err := meta.Accessor(obj)
if err != nil {
return nil, err
}
var (
debugID = fmt.Sprintf("%s/%s", meta.GetNamespace(), meta.GetName())
gvkLabel = meta.GetAnnotations()[LabelGVK]
namespace = meta.GetAnnotations()[LabelNamespace]
name = meta.GetAnnotations()[LabelName]
gvk schema.GroupVersionKind
)
if gvkLabel == "" {
return nil, ErrOwnerNotFound
}
if err := getGVK(gvkLabel, &gvk); err != nil {
return nil, err
}
cache, client, err := o.getControllerAndClient(debugID, gvk)
if err != nil {
return nil, err
}
if cache != nil {
return o.fromCache(cache, namespace, name, gvk)
}
return o.fromClient(client, namespace, name, gvk)
}
func (o *desiredSet) fromClient(client dynamic.NamespaceableResourceInterface, namespace, name string, gvk schema.GroupVersionKind) (runtime.Object, error) {
var (
err error
obj interface{}
)
if namespace == "" {
obj, err = client.Get(o.ctx, name, metav1.GetOptions{})
} else {
obj, err = client.Namespace(namespace).Get(o.ctx, name, metav1.GetOptions{})
}
if err != nil {
return nil, err
}
if ro, ok := obj.(runtime.Object); ok {
return ro, nil
}
return nil, notFound(name, gvk)
}
func (o *desiredSet) fromCache(cache cache.SharedInformer, namespace, name string, gvk schema.GroupVersionKind) (runtime.Object, error) {
var key string
if namespace == "" {
key = name
} else {
key = namespace + "/" + name
}
item, ok, err := cache.GetStore().GetByKey(key)
if err != nil {
return nil, err
} else if !ok {
return nil, notFound(name, gvk)
} else if ro, ok := item.(runtime.Object); ok {
return ro, nil
}
return nil, notFound(name, gvk)
}
func (o desiredSet) PurgeOrphan(obj runtime.Object) error {
if obj == nil {
return nil
}
meta, err := meta.Accessor(obj)
if err != nil {
return err
}
if _, err := o.FindOwner(obj); apierrors.IsNotFound(err) {
gvk, err := gvk.Get(obj)
if err != nil {
return err
}
o.strictCaching = false
_, client, err := o.getControllerAndClient(meta.GetName(), gvk)
if err != nil {
return err
}
if meta.GetNamespace() == "" {
return client.Delete(o.ctx, meta.GetName(), metav1.DeleteOptions{})
} else {
return client.Namespace(meta.GetNamespace()).Delete(o.ctx, meta.GetName(), metav1.DeleteOptions{})
}
} else if err == ErrOwnerNotFound {
return nil
} else if err != nil {
return err
}
return nil
}
...@@ -28,19 +28,27 @@ var ( ...@@ -28,19 +28,27 @@ var (
) )
func (o *desiredSet) getControllerAndClient(debugID string, gvk schema.GroupVersionKind) (cache.SharedIndexInformer, dynamic.NamespaceableResourceInterface, error) { func (o *desiredSet) getControllerAndClient(debugID string, gvk schema.GroupVersionKind) (cache.SharedIndexInformer, dynamic.NamespaceableResourceInterface, error) {
// client needs to be accessed first so that the gvk->gvr mapping gets cached
client, err := o.a.clients.client(gvk)
if err != nil {
return nil, nil, err
}
informer, ok := o.pruneTypes[gvk] informer, ok := o.pruneTypes[gvk]
if !ok { if !ok {
informer = o.a.informers[gvk] informer = o.a.informers[gvk]
} }
if informer == nil && o.informerFactory != nil {
newInformer, err := o.informerFactory.Get(gvk, o.a.clients.gvr(gvk))
if err != nil {
return nil, nil, errors.Wrapf(err, "failed to construct informer for %v for %s", gvk, debugID)
}
informer = newInformer
}
if informer == nil && o.strictCaching { if informer == nil && o.strictCaching {
return nil, nil, fmt.Errorf("failed to find informer for %s for %s", gvk, debugID) return nil, nil, fmt.Errorf("failed to find informer for %s for %s", gvk, debugID)
} }
client, err := o.a.clients.client(gvk)
if err != nil {
return nil, nil, err
}
return informer, client, nil return informer, client, nil
} }
...@@ -206,6 +214,8 @@ func (o *desiredSet) process(debugID string, set labels.Selector, gvk schema.Gro ...@@ -206,6 +214,8 @@ func (o *desiredSet) process(debugID string, set labels.Selector, gvk schema.Gro
patcher = o.createPatcher(client) patcher = o.createPatcher(client)
} }
reconciler := o.reconcilers[gvk]
existing, err := o.list(controller, client, set) existing, err := o.list(controller, client, set)
if err != nil { if err != nil {
o.err(errors.Wrapf(err, "failed to list %s for %s", gvk, debugID)) o.err(errors.Wrapf(err, "failed to list %s for %s", gvk, debugID))
...@@ -214,6 +224,26 @@ func (o *desiredSet) process(debugID string, set labels.Selector, gvk schema.Gro ...@@ -214,6 +224,26 @@ func (o *desiredSet) process(debugID string, set labels.Selector, gvk schema.Gro
toCreate, toDelete, toUpdate := compareSets(existing, objs) toCreate, toDelete, toUpdate := compareSets(existing, objs)
if o.createPlan {
o.plan.Create[gvk] = toCreate
o.plan.Delete[gvk] = toDelete
reconciler = nil
patcher = func(namespace, name string, pt types2.PatchType, data []byte) (runtime.Object, error) {
data, err := sanitizePatch(data, true)
if err != nil {
return nil, err
}
if string(data) != "{}" {
o.plan.Update.Add(gvk, namespace, name, string(data))
}
return nil, nil
}
toCreate = nil
toDelete = nil
}
createF := func(k objectset.ObjectKey) { createF := func(k objectset.ObjectKey) {
obj := objs[k] obj := objs[k]
obj, err := prepareObjectForCreate(gvk, obj) obj, err := prepareObjectForCreate(gvk, obj)
...@@ -248,7 +278,7 @@ func (o *desiredSet) process(debugID string, set labels.Selector, gvk schema.Gro ...@@ -248,7 +278,7 @@ func (o *desiredSet) process(debugID string, set labels.Selector, gvk schema.Gro
} }
updateF := func(k objectset.ObjectKey) { updateF := func(k objectset.ObjectKey) {
err := o.compareObjects(gvk, patcher, client, debugID, existing[k], objs[k], len(toCreate) > 0 || len(toDelete) > 0) err := o.compareObjects(gvk, reconciler, patcher, client, debugID, existing[k], objs[k], len(toCreate) > 0 || len(toDelete) > 0)
if err == ErrReplace { if err == ErrReplace {
deleteF(k, true) deleteF(k, true)
o.err(fmt.Errorf("DesiredSet - Replace Wait %s %s for %s", gvk, k, debugID)) o.err(fmt.Errorf("DesiredSet - Replace Wait %s %s for %s", gvk, k, debugID))
......
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"reflect" "reflect"
"time" "time"
"github.com/rancher/wrangler/pkg/generic"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
...@@ -14,7 +15,7 @@ func (c Cond) GetStatus(obj interface{}) string { ...@@ -14,7 +15,7 @@ func (c Cond) GetStatus(obj interface{}) string {
} }
func (c Cond) SetError(obj interface{}, reason string, err error) { func (c Cond) SetError(obj interface{}, reason string, err error) {
if err == nil { if err == nil || err == generic.ErrSkip {
c.True(obj) c.True(obj)
c.Message(obj, "") c.Message(obj, "")
c.Reason(obj, reason) c.Reason(obj, reason)
...@@ -153,6 +154,9 @@ func getTS(obj interface{}, condName string) string { ...@@ -153,6 +154,9 @@ func getTS(obj interface{}, condName string) string {
} }
func setStatus(obj interface{}, condName, status string) { func setStatus(obj interface{}, condName, status string) {
if reflect.TypeOf(obj).Kind() != reflect.Ptr {
panic("obj passed must be a pointer")
}
cond := findOrCreateCond(obj, condName) cond := findOrCreateCond(obj, condName)
setValue(cond, "Status", status) setValue(cond, "Status", status)
} }
...@@ -167,6 +171,9 @@ func setValue(cond reflect.Value, fieldName, newValue string) { ...@@ -167,6 +171,9 @@ func setValue(cond reflect.Value, fieldName, newValue string) {
func findOrNotCreateCond(obj interface{}, condName string) *reflect.Value { func findOrNotCreateCond(obj interface{}, condName string) *reflect.Value {
condSlice := getValue(obj, "Status", "Conditions") condSlice := getValue(obj, "Status", "Conditions")
if !condSlice.IsValid() {
condSlice = getValue(obj, "Conditions")
}
return findCond(obj, condSlice, condName) return findCond(obj, condSlice, condName)
} }
...@@ -224,6 +231,9 @@ func getValue(obj interface{}, name ...string) reflect.Value { ...@@ -224,6 +231,9 @@ func getValue(obj interface{}, name ...string) reflect.Value {
} }
func getFieldValue(v reflect.Value, name ...string) reflect.Value { func getFieldValue(v reflect.Value, name ...string) reflect.Value {
if !v.IsValid() {
return v
}
field := v.FieldByName(name[0]) field := v.FieldByName(name[0])
if len(name) == 1 { if len(name) == 1 {
return field return field
......
...@@ -85,18 +85,23 @@ func NewFactoryFromConfigOrDie(config *rest.Config) *Factory { ...@@ -85,18 +85,23 @@ func NewFactoryFromConfigOrDie(config *rest.Config) *Factory {
} }
func NewFactoryFromConfig(config *rest.Config) (*Factory, error) { func NewFactoryFromConfig(config *rest.Config) (*Factory, error) {
cs, err := clientset.NewForConfig(config) return NewFactoryFromConfigWithOptions(config, nil)
if err != nil {
return nil, err
}
informerFactory := informers.NewSharedInformerFactory(cs, 2*time.Hour)
return NewFactory(cs, informerFactory), nil
} }
func NewFactoryFromConfigWithNamespace(config *rest.Config, namespace string) (*Factory, error) { func NewFactoryFromConfigWithNamespace(config *rest.Config, namespace string) (*Factory, error) {
if namespace == "" { return NewFactoryFromConfigWithOptions(config, &FactoryOptions{
return NewFactoryFromConfig(config) Namespace: namespace,
})
}
type FactoryOptions struct {
Namespace string
Resync time.Duration
}
func NewFactoryFromConfigWithOptions(config *rest.Config, opts *FactoryOptions) (*Factory, error) {
if opts == nil {
opts = &FactoryOptions{}
} }
cs, err := clientset.NewForConfig(config) cs, err := clientset.NewForConfig(config)
...@@ -104,7 +109,17 @@ func NewFactoryFromConfigWithNamespace(config *rest.Config, namespace string) (* ...@@ -104,7 +109,17 @@ func NewFactoryFromConfigWithNamespace(config *rest.Config, namespace string) (*
return nil, err return nil, err
} }
informerFactory := informers.NewSharedInformerFactoryWithOptions(cs, 2*time.Hour, informers.WithNamespace(namespace)) resync := opts.Resync
if resync == 0 {
resync = 2*time.Hour
}
if opts.Namespace == "" {
informerFactory := informers.NewSharedInformerFactory(cs, resync)
return NewFactory(cs, informerFactory), nil
}
informerFactory := informers.NewSharedInformerFactoryWithOptions(cs, resync, informers.WithNamespace(opts.Namespace))
return NewFactory(cs, informerFactory), nil return NewFactory(cs, informerFactory), nil
} }
......
...@@ -333,6 +333,7 @@ func Register{{.type}}GeneratingHandler(ctx context.Context, controller {{.type} ...@@ -333,6 +333,7 @@ func Register{{.type}}GeneratingHandler(ctx context.Context, controller {{.type}
if opts != nil { if opts != nil {
statusHandler.opts = *opts statusHandler.opts = *opts
} }
controller.OnChange(ctx, name, statusHandler.Remove)
Register{{.type}}StatusHandler(ctx, controller, condition, name, statusHandler.Handle) Register{{.type}}StatusHandler(ctx, controller, condition, name, statusHandler.Handle)
} }
...@@ -347,7 +348,7 @@ func (a *{{.lowerName}}StatusHandler) sync(key string, obj *{{.version}}.{{.type ...@@ -347,7 +348,7 @@ func (a *{{.lowerName}}StatusHandler) sync(key string, obj *{{.version}}.{{.type
return obj, nil return obj, nil
} }
origStatus := obj.Status origStatus := obj.Status.DeepCopy()
obj = obj.DeepCopy() obj = obj.DeepCopy()
newStatus, err := a.handler(obj, obj.Status) newStatus, err := a.handler(obj, obj.Status)
if err != nil { if err != nil {
...@@ -355,16 +356,16 @@ func (a *{{.lowerName}}StatusHandler) sync(key string, obj *{{.version}}.{{.type ...@@ -355,16 +356,16 @@ func (a *{{.lowerName}}StatusHandler) sync(key string, obj *{{.version}}.{{.type
newStatus = *origStatus.DeepCopy() newStatus = *origStatus.DeepCopy()
} }
obj.Status = newStatus
if a.condition != "" { if a.condition != "" {
if errors.IsConflict(err) { if errors.IsConflict(err) {
a.condition.SetError(obj, "", nil) a.condition.SetError(&newStatus, "", nil)
} else { } else {
a.condition.SetError(obj, "", err) a.condition.SetError(&newStatus, "", err)
} }
} }
if !equality.Semantic.DeepEqual(origStatus, obj.Status) { if !equality.Semantic.DeepEqual(origStatus, &newStatus) {
var newErr error var newErr error
obj.Status = newStatus
obj, newErr = a.client.UpdateStatus(obj) obj, newErr = a.client.UpdateStatus(obj)
if err == nil { if err == nil {
err = newErr err = newErr
...@@ -381,29 +382,28 @@ type {{.lowerName}}GeneratingHandler struct { ...@@ -381,29 +382,28 @@ type {{.lowerName}}GeneratingHandler struct {
name string name string
} }
func (a *{{.lowerName}}GeneratingHandler) Handle(obj *{{.version}}.{{.type}}, status {{.version}}.{{.statusType}}) ({{.version}}.{{.statusType}}, error) { func (a *{{.lowerName}}GeneratingHandler) Remove(key string, obj *{{.version}}.{{.type}}) (*{{.version}}.{{.type}}, error) {
objs, newStatus, err := a.{{.type}}GeneratingHandler(obj, status) if obj != nil {
if err != nil { return obj, nil
return newStatus, err
} }
apply := a.apply obj = &{{.version}}.{{.type}}{}
obj.Namespace, obj.Name = kv.RSplit(key, "/")
if !a.opts.DynamicLookup { obj.SetGroupVersionKind(a.gvk)
apply = apply.WithStrictCaching()
}
if !a.opts.AllowCrossNamespace && !a.opts.AllowClusterScoped { return nil, generic.ConfigureApplyForObject(a.apply, obj, &a.opts).
apply = apply.WithSetOwnerReference(true, false). WithOwner(obj).
WithDefaultNamespace(obj.GetNamespace()). WithSetID(a.name).
WithListerNamespace(obj.GetNamespace()) ApplyObjects()
} }
if !a.opts.AllowClusterScoped { func (a *{{.lowerName}}GeneratingHandler) Handle(obj *{{.version}}.{{.type}}, status {{.version}}.{{.statusType}}) ({{.version}}.{{.statusType}}, error) {
apply = apply.WithRestrictClusterScoped() objs, newStatus, err := a.{{.type}}GeneratingHandler(obj, status)
if err != nil {
return newStatus, err
} }
return newStatus, apply. return newStatus, generic.ConfigureApplyForObject(a.apply, obj, &a.opts).
WithOwner(obj). WithOwner(obj).
WithSetID(a.name). WithSetID(a.name).
ApplyObjects(objs...) ApplyObjects(objs...)
......
...@@ -3,6 +3,7 @@ package crd ...@@ -3,6 +3,7 @@ package crd
import ( import (
"context" "context"
"reflect" "reflect"
"strconv"
"strings" "strings"
"sync" "sync"
"time" "time"
...@@ -16,7 +17,7 @@ import ( ...@@ -16,7 +17,7 @@ import (
apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
"k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/errors" apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
...@@ -52,8 +53,107 @@ func (c CRD) WithSchemaFromStruct(obj interface{}) CRD { ...@@ -52,8 +53,107 @@ func (c CRD) WithSchemaFromStruct(obj interface{}) CRD {
return c return c
} }
func (c CRD) WithCustomColumn(columns []v1beta1.CustomResourceColumnDefinition) CRD { func (c CRD) WithColumn(name, path string) CRD {
c.Columns = columns c.Columns = append(c.Columns, v1beta1.CustomResourceColumnDefinition{
Name: name,
Type: "string",
Priority: 0,
JSONPath: path,
})
return c
}
func getType(obj interface{}) reflect.Type {
if t, ok := obj.(reflect.Type); ok {
return t
}
t := reflect.TypeOf(obj)
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
return t
}
func (c CRD) WithColumnsFromStruct(obj interface{}) CRD {
c.Columns = append(c.Columns, readCustomColumns(getType(obj), ".")...)
return c
}
func fieldName(f reflect.StructField) string {
jsonTag := f.Tag.Get("json")
if jsonTag == "-" {
return ""
}
name := strings.Split(jsonTag, ",")[0]
if name == "" {
return f.Name
}
return name
}
func tagToColumn(f reflect.StructField) (v1beta1.CustomResourceColumnDefinition, bool) {
c := v1beta1.CustomResourceColumnDefinition{
Name: f.Name,
Type: "string",
}
columnDef, ok := f.Tag.Lookup("column")
if !ok {
return c, false
}
for k, v := range kv.SplitMap(columnDef, ",") {
switch k {
case "name":
c.Name = v
case "type":
c.Type = v
case "format":
c.Format = v
case "description":
c.Description = v
case "priority":
p, _ := strconv.Atoi(v)
c.Priority = int32(p)
case "jsonpath":
c.JSONPath = v
}
}
return c, true
}
func readCustomColumns(t reflect.Type, path string) (result []v1beta1.CustomResourceColumnDefinition) {
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
fieldName := fieldName(f)
if fieldName == "" {
continue
}
t := f.Type
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
if t.Kind() == reflect.Struct {
if f.Anonymous {
result = append(result, readCustomColumns(t, path)...)
} else {
result = append(result, readCustomColumns(t, path+"."+fieldName)...)
}
} else {
if col, ok := tagToColumn(f); ok {
result = append(result, col)
}
}
}
return result
}
func (c CRD) WithCustomColumn(columns ...v1beta1.CustomResourceColumnDefinition) CRD {
c.Columns = append(c.Columns, columns...)
return c return c
} }
...@@ -79,10 +179,7 @@ func (c CRD) WithShortNames(shortNames ...string) CRD { ...@@ -79,10 +179,7 @@ func (c CRD) WithShortNames(shortNames ...string) CRD {
func (c CRD) ToCustomResourceDefinition() (apiext.CustomResourceDefinition, error) { func (c CRD) ToCustomResourceDefinition() (apiext.CustomResourceDefinition, error) {
if c.SchemaObject != nil && c.GVK.Kind == "" { if c.SchemaObject != nil && c.GVK.Kind == "" {
t := reflect.TypeOf(c.SchemaObject) t := getType(c.SchemaObject)
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
c.GVK.Kind = t.Name() c.GVK.Kind = t.Name()
} }
...@@ -250,6 +347,13 @@ func (f *Factory) CreateCRDs(ctx context.Context, crds ...CRD) (map[schema.Group ...@@ -250,6 +347,13 @@ func (f *Factory) CreateCRDs(ctx context.Context, crds ...CRD) (map[schema.Group
return nil, nil return nil, nil
} }
if ok, err := f.ensureAccess(ctx); err != nil {
return nil, err
} else if !ok {
logrus.Infof("No access to list CRDs, assuming CRDs are pre-created.")
return nil, err
}
crdStatus := map[schema.GroupVersionKind]*apiext.CustomResourceDefinition{} crdStatus := map[schema.GroupVersionKind]*apiext.CustomResourceDefinition{}
ready, err := f.getReadyCRDs(ctx) ready, err := f.getReadyCRDs(ctx)
...@@ -341,7 +445,7 @@ func (f *Factory) createCRD(ctx context.Context, crdDef CRD, ready map[string]*a ...@@ -341,7 +445,7 @@ func (f *Factory) createCRD(ctx context.Context, crdDef CRD, ready map[string]*a
} }
logrus.Infof("Creating CRD %s", crd.Name) logrus.Infof("Creating CRD %s", crd.Name)
if newCrd, err := f.CRDClient.ApiextensionsV1beta1().CustomResourceDefinitions().Create(ctx, &crd, metav1.CreateOptions{}); errors.IsAlreadyExists(err) { if newCrd, err := f.CRDClient.ApiextensionsV1beta1().CustomResourceDefinitions().Create(ctx, &crd, metav1.CreateOptions{}); apierrors.IsAlreadyExists(err) {
return f.CRDClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(ctx, crd.Name, metav1.GetOptions{}) return f.CRDClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(ctx, crd.Name, metav1.GetOptions{})
} else if err != nil { } else if err != nil {
return nil, err return nil, err
...@@ -350,6 +454,14 @@ func (f *Factory) createCRD(ctx context.Context, crdDef CRD, ready map[string]*a ...@@ -350,6 +454,14 @@ func (f *Factory) createCRD(ctx context.Context, crdDef CRD, ready map[string]*a
} }
} }
func (f *Factory) ensureAccess(ctx context.Context) (bool, error) {
_, err := f.CRDClient.ApiextensionsV1beta1().CustomResourceDefinitions().List(ctx, metav1.ListOptions{})
if apierrors.IsForbidden(err) {
return false, nil
}
return true, err
}
func (f *Factory) getReadyCRDs(ctx context.Context) (map[string]*apiext.CustomResourceDefinition, error) { func (f *Factory) getReadyCRDs(ctx context.Context) (map[string]*apiext.CustomResourceDefinition, error) {
list, err := f.CRDClient.ApiextensionsV1beta1().CustomResourceDefinitions().List(ctx, metav1.ListOptions{}) list, err := f.CRDClient.ApiextensionsV1beta1().CustomResourceDefinitions().List(ctx, metav1.ListOptions{})
if err != nil { if err != nil {
......
package data
func MergeMaps(base, overlay map[string]interface{}) map[string]interface{} {
result := map[string]interface{}{}
for k, v := range base {
result[k] = v
}
for k, v := range overlay {
if baseMap, overlayMap, bothMaps := bothMaps(result[k], v); bothMaps {
v = MergeMaps(baseMap, overlayMap)
}
result[k] = v
}
return result
}
func bothMaps(left, right interface{}) (map[string]interface{}, map[string]interface{}, bool) {
leftMap, ok := left.(map[string]interface{})
if !ok {
return nil, nil, false
}
rightMap, ok := right.(map[string]interface{})
return leftMap, rightMap, ok
}
package generic package generic
import (
"github.com/rancher/wrangler/pkg/apply"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
type GeneratingHandlerOptions struct { type GeneratingHandlerOptions struct {
AllowCrossNamespace bool AllowCrossNamespace bool
AllowClusterScoped bool AllowClusterScoped bool
NoOwnerReference bool
DynamicLookup bool DynamicLookup bool
} }
func ConfigureApplyForObject(apply apply.Apply, obj metav1.Object, opts *GeneratingHandlerOptions) apply.Apply {
if opts == nil {
opts = &GeneratingHandlerOptions{}
}
if opts.DynamicLookup {
apply = apply.WithDynamicLookup()
}
if opts.NoOwnerReference {
apply = apply.WithSetOwnerReference(true, false)
}
if opts.AllowCrossNamespace && !opts.AllowClusterScoped {
apply = apply.
WithDefaultNamespace(obj.GetNamespace()).
WithListerNamespace(obj.GetNamespace())
}
if !opts.AllowClusterScoped {
apply = apply.WithRestrictClusterScoped()
}
return apply
}
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"reflect" "reflect"
"strings" "strings"
errors2 "github.com/pkg/errors"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
) )
...@@ -25,7 +26,7 @@ func (h *Handlers) Handle(key string, obj runtime.Object) (runtime.Object, error ...@@ -25,7 +26,7 @@ func (h *Handlers) Handle(key string, obj runtime.Object) (runtime.Object, error
for _, handler := range h.handlers { for _, handler := range h.handlers {
newObj, err := handler.handler(key, obj) newObj, err := handler.handler(key, obj)
if err != nil { if err != nil && errors2.Cause(err) != ErrSkip {
errs = append(errs, &handlerError{ errs = append(errs, &handlerError{
HandlerName: handler.name, HandlerName: handler.name,
Err: err, Err: err,
......
...@@ -27,7 +27,16 @@ func Get(obj runtime.Object) (schema.GroupVersionKind, error) { ...@@ -27,7 +27,16 @@ func Get(obj runtime.Object) (schema.GroupVersionKind, error) {
return gvks[0], nil return gvks[0], nil
} }
func Set(obj runtime.Object) error { func Set(objs ...runtime.Object) error {
for _, obj := range objs {
if err := setObject(obj); err != nil {
return err
}
}
return nil
}
func setObject(obj runtime.Object) error {
gvk := obj.GetObjectKind().GroupVersionKind() gvk := obj.GetObjectKind().GroupVersionKind()
if gvk.Kind != "" { if gvk.Kind != "" {
return nil return nil
......
...@@ -34,6 +34,8 @@ func (o ObjectKey) String() string { ...@@ -34,6 +34,8 @@ func (o ObjectKey) String() string {
return fmt.Sprintf("%s/%s", o.Namespace, o.Name) return fmt.Sprintf("%s/%s", o.Namespace, o.Name)
} }
type ObjectKeyByGVK map[schema.GroupVersionKind][]ObjectKey
type ObjectByGVK map[schema.GroupVersionKind]map[ObjectKey]runtime.Object type ObjectByGVK map[schema.GroupVersionKind]map[ObjectKey]runtime.Object
func (o ObjectByGVK) Add(obj runtime.Object) (schema.GroupVersionKind, error) { func (o ObjectByGVK) Add(obj runtime.Object) (schema.GroupVersionKind, error) {
...@@ -69,14 +71,19 @@ type ObjectSet struct { ...@@ -69,14 +71,19 @@ type ObjectSet struct {
gvkSeen map[schema.GroupVersionKind]bool gvkSeen map[schema.GroupVersionKind]bool
} }
func NewObjectSet() *ObjectSet { func NewObjectSet(objs ...runtime.Object) *ObjectSet {
return &ObjectSet{ os := &ObjectSet{
objects: ObjectByGVK{}, objects: ObjectByGVK{},
gvkSeen: map[schema.GroupVersionKind]bool{}, gvkSeen: map[schema.GroupVersionKind]bool{},
} }
os.Add(objs...)
return os
} }
func (o *ObjectSet) ObjectsByGVK() ObjectByGVK { func (o *ObjectSet) ObjectsByGVK() ObjectByGVK {
if o == nil {
return nil
}
return o.objects return o.objects
} }
...@@ -126,6 +133,10 @@ func (o *ObjectSet) Len() int { ...@@ -126,6 +133,10 @@ func (o *ObjectSet) Len() int {
return len(o.objects) return len(o.objects)
} }
func (o *ObjectSet) GVKs() []schema.GroupVersionKind {
return o.GVKOrder()
}
func (o *ObjectSet) GVKOrder(known ...schema.GroupVersionKind) []schema.GroupVersionKind { func (o *ObjectSet) GVKOrder(known ...schema.GroupVersionKind) []schema.GroupVersionKind {
var rest []schema.GroupVersionKind var rest []schema.GroupVersionKind
......
...@@ -36,7 +36,7 @@ func applyStrategicMergePatch(original, patch []byte, lookup strategicpatch.Look ...@@ -36,7 +36,7 @@ func applyStrategicMergePatch(original, patch []byte, lookup strategicpatch.Look
if err := json.Unmarshal(patch, &patchMap); err != nil { if err := json.Unmarshal(patch, &patchMap); err != nil {
return nil, err return nil, err
} }
patchedMap, err := strategicpatch.StrategicMergeMapPatch(originalMap, patchMap, lookup) patchedMap, err := strategicpatch.StrategicMergeMapPatchUsingLookupPatchMeta(originalMap, patchMap, lookup)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
package openapi package openapi
import ( import (
"encoding/json"
"fmt" "fmt"
types "github.com/rancher/wrangler/pkg/schemas" types "github.com/rancher/wrangler/pkg/schemas"
...@@ -8,6 +9,14 @@ import ( ...@@ -8,6 +9,14 @@ import (
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
) )
var (
blacklistFields = map[string]bool{
"kind": true,
"apiVersion": true,
"metadata": true,
}
)
func MustGenerate(obj interface{}) *v1beta1.JSONSchemaProps { func MustGenerate(obj interface{}) *v1beta1.JSONSchemaProps {
if obj == nil { if obj == nil {
return nil return nil
...@@ -42,178 +51,169 @@ func toOpenAPI(name string, schemas *types.Schemas) (*v1beta1.JSONSchemaProps, e ...@@ -42,178 +51,169 @@ func toOpenAPI(name string, schemas *types.Schemas) (*v1beta1.JSONSchemaProps, e
delete(newSchema.ResourceFields, "kind") delete(newSchema.ResourceFields, "kind")
delete(newSchema.ResourceFields, "apiVersion") delete(newSchema.ResourceFields, "apiVersion")
delete(newSchema.ResourceFields, "metadata") delete(newSchema.ResourceFields, "metadata")
return parseSchema(newSchema, schemas)
return schemaToProps(newSchema, schemas, map[string]bool{})
} }
func parseSchema(schema *types.Schema, schemas *types.Schemas) (*v1beta1.JSONSchemaProps, error) { func populateField(fieldJSP *v1beta1.JSONSchemaProps, f *types.Field) error {
jsp := &v1beta1.JSONSchemaProps{ fieldJSP.Description = f.Description
Description: schema.Description, // don't reset this to not nullable
Type: "object", if f.Nullable {
Properties: map[string]v1beta1.JSONSchemaProps{}, fieldJSP.Nullable = f.Nullable
} }
fieldJSP.MinLength = f.MinLength
fieldJSP.MaxLength = f.MaxLength
for name, f := range schema.ResourceFields { if f.Type == "string" && len(f.Options) > 0 {
fieldJSP := v1beta1.JSONSchemaProps{ for _, opt := range append(f.Options, "") {
Description: f.Description, bytes, err := json.Marshal(&opt)
Nullable: f.Nullable, if err != nil {
MinLength: f.MinLength, return err
MaxLength: f.MaxLength,
}
if len(f.Options) > 0 {
for _, opt := range f.Options {
fieldJSP.Enum = append(fieldJSP.Enum, v1beta1.JSON{
Raw: []byte(opt),
})
} }
fieldJSP.Enum = append(fieldJSP.Enum, v1beta1.JSON{
Raw: bytes,
})
} }
}
if len(f.InvalidChars) > 0 { if len(f.InvalidChars) > 0 {
fieldJSP.Pattern = fmt.Sprintf("^[^%s]*$", f.InvalidChars) fieldJSP.Pattern = fmt.Sprintf("^[^%s]*$", f.InvalidChars)
} }
if len(f.ValidChars) > 0 { if len(f.ValidChars) > 0 {
fieldJSP.Pattern = fmt.Sprintf("^[%s]*$", f.ValidChars) fieldJSP.Pattern = fmt.Sprintf("^[%s]*$", f.ValidChars)
} }
if f.Min != nil { if f.Min != nil {
fl := float64(*f.Min) fl := float64(*f.Min)
fieldJSP.Minimum = &fl fieldJSP.Minimum = &fl
} }
if f.Max != nil { if f.Max != nil {
fl := float64(*f.Max) fl := float64(*f.Max)
fieldJSP.Maximum = &fl fieldJSP.Maximum = &fl
} }
// default is not support by k8s return nil
// }
//if f.Default != nil {
// bytes, err := json.Marshal(f.Default)
// if err != nil {
// return nil, err
// }
// fieldJSP.Default = &v1beta1.JSON{
// Raw: bytes,
// }
//}
if f.Required { func typeToProps(typeName string, schemas *types.Schemas, inflight map[string]bool) (*v1beta1.JSONSchemaProps, error) {
fieldJSP.Required = append(fieldJSP.Required, name) t, subType, schema, err := typeAndSchema(typeName, schemas)
if err != nil {
return nil, err
}
if schema != nil {
return schemaToProps(schema, schemas, inflight)
}
jsp := &v1beta1.JSONSchemaProps{}
switch t {
case "map":
additionalProps, err := typeToProps(subType, schemas, inflight)
if err != nil {
return nil, err
}
jsp.Type = "object"
jsp.Nullable = true
jsp.AdditionalProperties = &v1beta1.JSONSchemaPropsOrBool{
Schema: additionalProps,
}
case "array":
items, err := typeToProps(subType, schemas, inflight)
if err != nil {
return nil, err
} }
jsp.Type = "array"
jsp.Nullable = true
jsp.Items = &v1beta1.JSONSchemaPropsOrArray{
Schema: items,
}
default:
jsp.Type = t
}
if definition.IsMapType(f.Type) { return jsp, nil
fieldJSP.Type = "object" }
subType := definition.SubType(f.Type)
subType, schema, err := typeAndSchema(subType, schemas) func schemaToProps(schema *types.Schema, schemas *types.Schemas, inflight map[string]bool) (*v1beta1.JSONSchemaProps, error) {
if err != nil { jsp := &v1beta1.JSONSchemaProps{
return nil, err Description: schema.Description,
} Type: "object",
}
if schema == nil { if inflight[schema.ID] {
fieldJSP.AdditionalProperties = &v1beta1.JSONSchemaPropsOrBool{ return jsp, nil
Schema: &v1beta1.JSONSchemaProps{ }
Type: subType,
},
}
} else {
subObject, err := parseSchema(schema, schemas)
if err != nil {
return nil, err
}
fieldJSP.AdditionalProperties = &v1beta1.JSONSchemaPropsOrBool{
Schema: subObject,
}
}
} else if definition.IsArrayType(f.Type) {
fieldJSP.Type = "array"
subType := definition.SubType(f.Type)
subType, schema, err := typeAndSchema(subType, schemas) inflight[schema.ID] = true
if err != nil { defer delete(inflight, schema.ID)
return nil, err
}
if schema == nil { jsp.Properties = map[string]v1beta1.JSONSchemaProps{}
fieldJSP.Items = &v1beta1.JSONSchemaPropsOrArray{
Schema: &v1beta1.JSONSchemaProps{
Type: subType,
},
}
} else {
subObject, err := parseSchema(schema, schemas)
if err != nil {
return nil, err
}
fieldJSP.Items = &v1beta1.JSONSchemaPropsOrArray{
Schema: subObject,
}
}
} else {
typeName, schema, err := typeAndSchema(f.Type, schemas)
if err != nil {
return nil, err
}
if schema == nil {
fieldJSP.Type = typeName
} else {
fieldJSP.Type = "object"
subObject, err := parseSchema(schema, schemas)
if err != nil {
return nil, err
}
fieldJSP.Properties = subObject.Properties
}
}
jsp.Properties[name] = fieldJSP for name, f := range schema.ResourceFields {
fieldJSP, err := typeToProps(f.Type, schemas, inflight)
if err != nil {
return nil, err
}
if err := populateField(fieldJSP, &f); err != nil {
return nil, err
}
if f.Required {
jsp.Required = append(jsp.Required, name)
}
jsp.Properties[name] = *fieldJSP
} }
return jsp, nil return jsp, nil
} }
func typeAndSchema(typeName string, schemas *types.Schemas) (string, *types.Schema, error) { func typeAndSchema(typeName string, schemas *types.Schemas) (string, string, *types.Schema, error) {
if definition.IsReferenceType(typeName) {
return "string", "", nil, nil
}
if definition.IsArrayType(typeName) {
return "array", definition.SubType(typeName), nil, nil
}
if definition.IsMapType(typeName) {
return "map", definition.SubType(typeName), nil, nil
}
switch typeName { switch typeName {
// TODO: in v1 set the x- header for this // TODO: in v1 set the x- header for this
case "intOrString": case "intOrString":
return "string", nil, nil return "string", "", nil, nil
case "int": case "int":
return "integer", nil, nil return "integer", "", nil, nil
case "float": case "float":
return "number", nil, nil return "number", "", nil, nil
case "string": case "string":
return "string", nil, nil return "string", "", nil, nil
case "date": case "date":
return "string", nil, nil return "string", "", nil, nil
case "enum": case "enum":
return "string", nil, nil return "string", "", nil, nil
case "base64":
return "string", "", nil, nil
case "password": case "password":
return "string", nil, nil return "string", "", nil, nil
case "hostname": case "hostname":
return "string", nil, nil return "string", "", nil, nil
case "boolean": case "boolean":
return "boolean", nil, nil return "boolean", "", nil, nil
case "json": case "json":
return "object", nil, nil return "object", "", nil, nil
}
if definition.IsReferenceType(typeName) {
return "string", nil, nil
}
if definition.IsArrayType(typeName) {
return "array", nil, nil
} }
schema := schemas.Schema(typeName) schema := schemas.Schema(typeName)
if schema == nil { if schema == nil {
return "", nil, fmt.Errorf("failed to find schema %s", typeName) return "", "", nil, fmt.Errorf("failed to find schema %s", typeName)
} }
if schema.InternalSchema != nil { if schema.InternalSchema != nil {
return "", schema.InternalSchema, nil return "", "", schema.InternalSchema, nil
} }
return "", schema, nil return "", "", schema, nil
} }
...@@ -64,23 +64,25 @@ func (s *Schemas) MustImportAndCustomize(obj interface{}, f func(*Schema), exter ...@@ -64,23 +64,25 @@ func (s *Schemas) MustImportAndCustomize(obj interface{}, f func(*Schema), exter
MustCustomizeType(obj, f) MustCustomizeType(obj, f)
} }
func (s *Schemas) Import(obj interface{}, externalOverrides ...interface{}) (*Schema, error) { func getType(obj interface{}) reflect.Type {
var types []reflect.Type if t, ok := obj.(reflect.Type); ok {
for _, override := range externalOverrides { return t
types = append(types, reflect.TypeOf(override))
} }
var ( t := reflect.TypeOf(obj)
v = reflect.ValueOf(obj) if t.Kind() == reflect.Ptr {
t reflect.Type t = t.Elem()
) }
return t
}
if v.Kind() == reflect.Ptr { func (s *Schemas) Import(obj interface{}, externalOverrides ...interface{}) (*Schema, error) {
t = v.Elem().Type() var types []reflect.Type
} else { for _, override := range externalOverrides {
t = v.Type() types = append(types, getType(override))
} }
t := getType(obj)
return s.importType(t, types...) return s.importType(t, types...)
} }
...@@ -320,6 +322,9 @@ func (s *Schemas) readFields(schema *Schema, t reflect.Type) error { ...@@ -320,6 +322,9 @@ func (s *Schemas) readFields(schema *Schema, t reflect.Type) error {
} }
if hasType && hasMeta { if hasType && hasMeta {
delete(schema.ResourceFields, "kind")
delete(schema.ResourceFields, "apiVersion")
delete(schema.ResourceFields, "metadata")
schema.CollectionMethods = []string{"GET", "POST"} schema.CollectionMethods = []string{"GET", "POST"}
schema.ResourceMethods = []string{"GET", "PUT", "DELETE"} schema.ResourceMethods = []string{"GET", "PUT", "DELETE"}
} }
...@@ -357,7 +362,11 @@ func (s *Schemas) processFieldsMappers(t reflect.Type, fieldName string, schema ...@@ -357,7 +362,11 @@ func (s *Schemas) processFieldsMappers(t reflect.Type, fieldName string, schema
} }
func applyTag(structField *reflect.StructField, field *Field) error { func applyTag(structField *reflect.StructField, field *Field) error {
for _, part := range strings.Split(structField.Tag.Get("norman"), ",") { t, ok := structField.Tag.Lookup("wrangler")
if !ok {
t = structField.Tag.Get("norman")
}
for _, part := range strings.Split(t, ",") {
if part == "" { if part == "" {
continue continue
} }
......
...@@ -716,7 +716,7 @@ github.com/rancher/dynamiclistener/factory ...@@ -716,7 +716,7 @@ github.com/rancher/dynamiclistener/factory
github.com/rancher/dynamiclistener/storage/file github.com/rancher/dynamiclistener/storage/file
github.com/rancher/dynamiclistener/storage/kubernetes github.com/rancher/dynamiclistener/storage/kubernetes
github.com/rancher/dynamiclistener/storage/memory github.com/rancher/dynamiclistener/storage/memory
# github.com/rancher/helm-controller v0.4.2-0.20200326195131-eb51d4fa9d8d # github.com/rancher/helm-controller v0.5.0
github.com/rancher/helm-controller/pkg/apis/helm.cattle.io github.com/rancher/helm-controller/pkg/apis/helm.cattle.io
github.com/rancher/helm-controller/pkg/apis/helm.cattle.io/v1 github.com/rancher/helm-controller/pkg/apis/helm.cattle.io/v1
github.com/rancher/helm-controller/pkg/generated/clientset/versioned github.com/rancher/helm-controller/pkg/generated/clientset/versioned
...@@ -745,7 +745,7 @@ github.com/rancher/kine/pkg/server ...@@ -745,7 +745,7 @@ github.com/rancher/kine/pkg/server
github.com/rancher/kine/pkg/tls github.com/rancher/kine/pkg/tls
# github.com/rancher/remotedialer v0.2.0 # github.com/rancher/remotedialer v0.2.0
github.com/rancher/remotedialer github.com/rancher/remotedialer
# github.com/rancher/wrangler v0.5.4-0.20200326191509-4054411d9736 # github.com/rancher/wrangler v0.6.1
github.com/rancher/wrangler/pkg/apply github.com/rancher/wrangler/pkg/apply
github.com/rancher/wrangler/pkg/apply/injectors github.com/rancher/wrangler/pkg/apply/injectors
github.com/rancher/wrangler/pkg/cleanup github.com/rancher/wrangler/pkg/cleanup
...@@ -773,7 +773,7 @@ github.com/rancher/wrangler/pkg/schemes ...@@ -773,7 +773,7 @@ github.com/rancher/wrangler/pkg/schemes
github.com/rancher/wrangler/pkg/signals github.com/rancher/wrangler/pkg/signals
github.com/rancher/wrangler/pkg/slice github.com/rancher/wrangler/pkg/slice
github.com/rancher/wrangler/pkg/start github.com/rancher/wrangler/pkg/start
# github.com/rancher/wrangler-api v0.5.1-0.20200326194427-c13310506d04 # github.com/rancher/wrangler-api v0.6.0
github.com/rancher/wrangler-api/pkg/generated/controllers/apps github.com/rancher/wrangler-api/pkg/generated/controllers/apps
github.com/rancher/wrangler-api/pkg/generated/controllers/apps/v1 github.com/rancher/wrangler-api/pkg/generated/controllers/apps/v1
github.com/rancher/wrangler-api/pkg/generated/controllers/batch github.com/rancher/wrangler-api/pkg/generated/controllers/batch
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment