mirror of https://github.com/knative/caching.git
Auto-update dependencies (#203)
Produced via: `dep ensure -update knative.dev/test-infra knative.dev/pkg` /assign n3wscott /cc n3wscott
This commit is contained in:
parent
1094caadae
commit
8b0cd41569
|
@ -966,7 +966,7 @@
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:9baf7494df34e555a6a2c9ab5c951a7b07c593d8176a679eab98897b1bb50d0d"
|
digest = "1:e71caa2e846cf80d5c362a7189f6a9276f8d60b96dd95b52a11ac321270098f6"
|
||||||
name = "knative.dev/pkg"
|
name = "knative.dev/pkg"
|
||||||
packages = [
|
packages = [
|
||||||
"apis",
|
"apis",
|
||||||
|
@ -983,20 +983,21 @@
|
||||||
"logging/logkey",
|
"logging/logkey",
|
||||||
"metrics",
|
"metrics",
|
||||||
"metrics/metricskey",
|
"metrics/metricskey",
|
||||||
|
"reconciler",
|
||||||
]
|
]
|
||||||
pruneopts = "T"
|
pruneopts = "T"
|
||||||
revision = "a447f39709f1ee8c1854517c247330b8ecb9a6ca"
|
revision = "602d92f69b660a5a84cbe96a9be21723f6f52d3d"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:d2545cd71ef3604f5d2d792e569c6e3a4df31e336d76e709b0b8bac759c0faf7"
|
digest = "1:691951c6805590983ccea7c6dbca360bcb58af5f4d60f75af9499903bb3039e9"
|
||||||
name = "knative.dev/test-infra"
|
name = "knative.dev/test-infra"
|
||||||
packages = [
|
packages = [
|
||||||
"scripts",
|
"scripts",
|
||||||
"tools/dep-collector",
|
"tools/dep-collector",
|
||||||
]
|
]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "c7c50ccd8082344a5f8ea85a5ae8de59308d325c"
|
revision = "279d938f5e19db2550bea7f71f4cdb97e0d84128"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:8730e0150dfb2b7e173890c8b9868e7a273082ef8e39f4940e3506a481cf895c"
|
digest = "1:8730e0150dfb2b7e173890c8b9868e7a273082ef8e39f4940e3506a481cf895c"
|
||||||
|
|
|
@ -422,14 +422,6 @@
|
||||||
revision = "24b83195037b3bc61fcda2d28b7b0518bce293b6"
|
revision = "24b83195037b3bc61fcda2d28b7b0518bce293b6"
|
||||||
version = "v1.0.4"
|
version = "v1.0.4"
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
digest = "1:0e9bfc47ab9941ecc3344e580baca5deb4091177e84dd9773b48b38ec26b93d5"
|
|
||||||
name = "github.com/mattbaird/jsonpatch"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "NUT"
|
|
||||||
revision = "81af80346b1a01caae0cbc27fd3c1ba5b11e189f"
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:5985ef4caf91ece5d54817c11ea25f182697534f8ae6521eadcd628c142ac4b6"
|
digest = "1:5985ef4caf91ece5d54817c11ea25f182697534f8ae6521eadcd628c142ac4b6"
|
||||||
name = "github.com/matttproud/golang_protobuf_extensions"
|
name = "github.com/matttproud/golang_protobuf_extensions"
|
||||||
|
@ -752,6 +744,14 @@
|
||||||
pruneopts = "NUT"
|
pruneopts = "NUT"
|
||||||
revision = "8b927904ee0dec805c89aaf9172f4459296ed6e8"
|
revision = "8b927904ee0dec805c89aaf9172f4459296ed6e8"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:8392b5c29adedc5f85c66b48bb53b6c49dd91d8540f3cad5d43ef7277946718f"
|
||||||
|
name = "gomodules.xyz/jsonpatch"
|
||||||
|
packages = ["v2"]
|
||||||
|
pruneopts = "NUT"
|
||||||
|
revision = "e8422f09d27ee2c8cfb2c7f8089eb9eeb0764849"
|
||||||
|
version = "v2.0.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:081608ceb454c46b54d24b7561e5744088f3ff69478b23f50277ec83bd8636b0"
|
digest = "1:081608ceb454c46b54d24b7561e5744088f3ff69478b23f50277ec83bd8636b0"
|
||||||
name = "google.golang.org/api"
|
name = "google.golang.org/api"
|
||||||
|
@ -1323,14 +1323,14 @@
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:9fc1b7e84778267884b614c45b0939aa8984dcab5794eb3c6bb5e57bd0a99c41"
|
digest = "1:d2545cd71ef3604f5d2d792e569c6e3a4df31e336d76e709b0b8bac759c0faf7"
|
||||||
name = "knative.dev/test-infra"
|
name = "knative.dev/test-infra"
|
||||||
packages = [
|
packages = [
|
||||||
"scripts",
|
"scripts",
|
||||||
"tools/dep-collector",
|
"tools/dep-collector",
|
||||||
]
|
]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "1b5477b12d75ea7210d970ff9a234277dcd9ee18"
|
revision = "c7c50ccd8082344a5f8ea85a5ae8de59308d325c"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:8730e0150dfb2b7e173890c8b9868e7a273082ef8e39f4940e3506a481cf895c"
|
digest = "1:8730e0150dfb2b7e173890c8b9868e7a273082ef8e39f4940e3506a481cf895c"
|
||||||
|
@ -1371,7 +1371,6 @@
|
||||||
"github.com/gorilla/websocket",
|
"github.com/gorilla/websocket",
|
||||||
"github.com/kballard/go-shellquote",
|
"github.com/kballard/go-shellquote",
|
||||||
"github.com/markbates/inflect",
|
"github.com/markbates/inflect",
|
||||||
"github.com/mattbaird/jsonpatch",
|
|
||||||
"github.com/openzipkin/zipkin-go",
|
"github.com/openzipkin/zipkin-go",
|
||||||
"github.com/openzipkin/zipkin-go/model",
|
"github.com/openzipkin/zipkin-go/model",
|
||||||
"github.com/openzipkin/zipkin-go/reporter",
|
"github.com/openzipkin/zipkin-go/reporter",
|
||||||
|
@ -1397,6 +1396,7 @@
|
||||||
"golang.org/x/net/http2/h2c",
|
"golang.org/x/net/http2/h2c",
|
||||||
"golang.org/x/oauth2",
|
"golang.org/x/oauth2",
|
||||||
"golang.org/x/sync/errgroup",
|
"golang.org/x/sync/errgroup",
|
||||||
|
"gomodules.xyz/jsonpatch/v2",
|
||||||
"google.golang.org/api/container/v1beta1",
|
"google.golang.org/api/container/v1beta1",
|
||||||
"google.golang.org/api/iterator",
|
"google.golang.org/api/iterator",
|
||||||
"google.golang.org/api/option",
|
"google.golang.org/api/option",
|
||||||
|
|
|
@ -20,7 +20,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
jsonmergepatch "github.com/evanphx/json-patch"
|
jsonmergepatch "github.com/evanphx/json-patch"
|
||||||
"github.com/mattbaird/jsonpatch"
|
jsonpatch "gomodules.xyz/jsonpatch/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func marshallBeforeAfter(before, after interface{}) ([]byte, []byte, error) {
|
func marshallBeforeAfter(before, after interface{}) ([]byte, []byte, error) {
|
||||||
|
|
|
@ -125,6 +125,18 @@ func (g *reconcilerControllerGenerator) GenerateType(c *generator.Context, t *ty
|
||||||
Package: "knative.dev/pkg/controller",
|
Package: "knative.dev/pkg/controller",
|
||||||
Name: "GetEventRecorder",
|
Name: "GetEventRecorder",
|
||||||
}),
|
}),
|
||||||
|
"controllerOptions": c.Universe.Type(types.Name{
|
||||||
|
Package: "knative.dev/pkg/controller",
|
||||||
|
Name: "Options",
|
||||||
|
}),
|
||||||
|
"controllerOptionsFn": c.Universe.Type(types.Name{
|
||||||
|
Package: "knative.dev/pkg/controller",
|
||||||
|
Name: "OptionsFn",
|
||||||
|
}),
|
||||||
|
"contextContext": c.Universe.Type(types.Name{
|
||||||
|
Package: "context",
|
||||||
|
Name: "Context",
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
sw.Do(reconcilerControllerNewImpl, m)
|
sw.Do(reconcilerControllerNewImpl, m)
|
||||||
|
@ -141,9 +153,16 @@ const (
|
||||||
|
|
||||||
// NewImpl returns a {{.controllerImpl|raw}} that handles queuing and feeding work from
|
// NewImpl returns a {{.controllerImpl|raw}} that handles queuing and feeding work from
|
||||||
// the queue through an implementation of {{.controllerReconciler|raw}}, delegating to
|
// the queue through an implementation of {{.controllerReconciler|raw}}, delegating to
|
||||||
// the provided Interface and optional Finalizer methods.
|
// the provided Interface and optional Finalizer methods. OptionsFn is used to return
|
||||||
func NewImpl(ctx context.Context, r Interface) *{{.controllerImpl|raw}} {
|
// {{.controllerOptions|raw}} to be used but the internal reconciler.
|
||||||
|
func NewImpl(ctx {{.contextContext|raw}}, r Interface, optionsFns ...{{.controllerOptionsFn|raw}}) *{{.controllerImpl|raw}} {
|
||||||
logger := {{.loggingFromContext|raw}}(ctx)
|
logger := {{.loggingFromContext|raw}}(ctx)
|
||||||
|
|
||||||
|
// Check the options function input. It should be 0 or 1.
|
||||||
|
if len(optionsFns) > 1 {
|
||||||
|
logger.Fatalf("up to one options function is supported, found %d", len(optionsFns))
|
||||||
|
}
|
||||||
|
|
||||||
{{.type|lowercaseSingular}}Informer := {{.informerGet|raw}}(ctx)
|
{{.type|lowercaseSingular}}Informer := {{.informerGet|raw}}(ctx)
|
||||||
|
|
||||||
recorder := {{.controllerGetEventRecorder|raw}}(ctx)
|
recorder := {{.controllerGetEventRecorder|raw}}(ctx)
|
||||||
|
@ -171,7 +190,17 @@ func NewImpl(ctx context.Context, r Interface) *{{.controllerImpl|raw}} {
|
||||||
Recorder: recorder,
|
Recorder: recorder,
|
||||||
reconciler: r,
|
reconciler: r,
|
||||||
}
|
}
|
||||||
return {{.controllerNewImpl|raw}}(rec, logger, defaultQueueName)
|
impl := {{.controllerNewImpl|raw}}(rec, logger, defaultQueueName)
|
||||||
|
|
||||||
|
// Pass impl to the options. Save any optional results.
|
||||||
|
for _, fn := range optionsFns {
|
||||||
|
opts := fn(impl)
|
||||||
|
if opts.ConfigStore != nil {
|
||||||
|
rec.configStore = opts.ConfigStore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return impl
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
|
@ -75,6 +75,14 @@ func (g *reconcilerControllerStubGenerator) GenerateType(c *generator.Context, t
|
||||||
Package: "knative.dev/pkg/logging",
|
Package: "knative.dev/pkg/logging",
|
||||||
Name: "FromContext",
|
Name: "FromContext",
|
||||||
}),
|
}),
|
||||||
|
"contextContext": c.Universe.Type(types.Name{
|
||||||
|
Package: "context",
|
||||||
|
Name: "Context",
|
||||||
|
}),
|
||||||
|
"configmapWatcher": c.Universe.Type(types.Name{
|
||||||
|
Package: "knative.dev/pkg/configmap",
|
||||||
|
Name: "Watcher",
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
sw.Do(reconcilerControllerStub, m)
|
sw.Do(reconcilerControllerStub, m)
|
||||||
|
@ -87,8 +95,8 @@ var reconcilerControllerStub = `
|
||||||
|
|
||||||
// NewController creates a Reconciler for {{.type|public}} and returns the result of NewImpl.
|
// NewController creates a Reconciler for {{.type|public}} and returns the result of NewImpl.
|
||||||
func NewController(
|
func NewController(
|
||||||
ctx context.Context,
|
ctx {{.contextContext|raw}},
|
||||||
cmw configmap.Watcher,
|
cmw {{.configmapWatcher|raw}},
|
||||||
) *{{.controllerImpl|raw}} {
|
) *{{.controllerImpl|raw}} {
|
||||||
logger := {{.loggingFromContext|raw}}(ctx)
|
logger := {{.loggingFromContext|raw}}(ctx)
|
||||||
|
|
||||||
|
|
|
@ -82,10 +82,10 @@ func (g *reconcilerReconcilerGenerator) GenerateType(c *generator.Context, t *ty
|
||||||
Package: "k8s.io/api/core/v1",
|
Package: "k8s.io/api/core/v1",
|
||||||
Name: "EventTypeWarning",
|
Name: "EventTypeWarning",
|
||||||
}),
|
}),
|
||||||
"reconcilerEvent": c.Universe.Type(types.Name{Package: "knative.dev/pkg/reconciler", Name: "Event"}),
|
"reconcilerEvent": c.Universe.Type(types.Name{Package: "knative.dev/pkg/reconciler", Name: "Event"}),
|
||||||
"reconcilerReconcilerEvent": c.Universe.Type(types.Name{Package: "knative.dev/pkg/reconciler", Name: "ReconcilerEvent"}),
|
"reconcilerReconcilerEvent": c.Universe.Type(types.Name{Package: "knative.dev/pkg/reconciler", Name: "ReconcilerEvent"}),
|
||||||
|
|
||||||
"reconcilerRetryUpdateConflicts": c.Universe.Function(types.Name{Package: "knative.dev/pkg/reconciler", Name: "RetryUpdateConflicts"}),
|
"reconcilerRetryUpdateConflicts": c.Universe.Function(types.Name{Package: "knative.dev/pkg/reconciler", Name: "RetryUpdateConflicts"}),
|
||||||
|
"reconcilerConfigStore": c.Universe.Type(types.Name{Name: "ConfigStore", Package: "knative.dev/pkg/reconciler"}),
|
||||||
// Deps
|
// Deps
|
||||||
"clientsetInterface": c.Universe.Type(types.Name{Name: "Interface", Package: g.clientsetPkg}),
|
"clientsetInterface": c.Universe.Type(types.Name{Name: "Interface", Package: g.clientsetPkg}),
|
||||||
"resourceLister": c.Universe.Type(types.Name{Name: g.listerName, Package: g.listerPkg}),
|
"resourceLister": c.Universe.Type(types.Name{Name: g.listerName, Package: g.listerPkg}),
|
||||||
|
@ -120,6 +120,14 @@ func (g *reconcilerReconcilerGenerator) GenerateType(c *generator.Context, t *ty
|
||||||
Package: "k8s.io/apimachinery/pkg/util/sets",
|
Package: "k8s.io/apimachinery/pkg/util/sets",
|
||||||
Name: "NewString",
|
Name: "NewString",
|
||||||
}),
|
}),
|
||||||
|
"controllerOptions": c.Universe.Type(types.Name{
|
||||||
|
Package: "knative.dev/pkg/controller",
|
||||||
|
Name: "Options",
|
||||||
|
}),
|
||||||
|
"contextContext": c.Universe.Type(types.Name{
|
||||||
|
Package: "context",
|
||||||
|
Name: "Context",
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
sw.Do(reconcilerInterfaceFactory, m)
|
sw.Do(reconcilerInterfaceFactory, m)
|
||||||
|
@ -141,7 +149,7 @@ type Interface interface {
|
||||||
// for the Kind inside of ReconcileKind, it is the responsibility of the calling
|
// for the Kind inside of ReconcileKind, it is the responsibility of the calling
|
||||||
// controller to propagate those properties. The resource passed to ReconcileKind
|
// controller to propagate those properties. The resource passed to ReconcileKind
|
||||||
// will always have an empty deletion timestamp.
|
// will always have an empty deletion timestamp.
|
||||||
ReconcileKind(ctx context.Context, o *{{.type|raw}}) {{.reconcilerEvent|raw}}
|
ReconcileKind(ctx {{.contextContext|raw}}, o *{{.type|raw}}) {{.reconcilerEvent|raw}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finalizer defines the strongly typed interfaces to be implemented by a
|
// Finalizer defines the strongly typed interfaces to be implemented by a
|
||||||
|
@ -152,7 +160,7 @@ type Finalizer interface {
|
||||||
// Normal type {{.reconcilerEvent|raw}} will allow the finalizer to be deleted on
|
// Normal type {{.reconcilerEvent|raw}} will allow the finalizer to be deleted on
|
||||||
// the resource. The resource passed to FinalizeKind will always have a set
|
// the resource. The resource passed to FinalizeKind will always have a set
|
||||||
// deletion timestamp.
|
// deletion timestamp.
|
||||||
FinalizeKind(ctx context.Context, o *{{.type|raw}}) {{.reconcilerEvent|raw}}
|
FinalizeKind(ctx {{.contextContext|raw}}, o *{{.type|raw}}) {{.reconcilerEvent|raw}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// reconcilerImpl implements controller.Reconciler for {{.type|raw}} resources.
|
// reconcilerImpl implements controller.Reconciler for {{.type|raw}} resources.
|
||||||
|
@ -167,6 +175,10 @@ type reconcilerImpl struct {
|
||||||
// Kubernetes API.
|
// Kubernetes API.
|
||||||
Recorder {{.recordEventRecorder|raw}}
|
Recorder {{.recordEventRecorder|raw}}
|
||||||
|
|
||||||
|
// configStore allows for decorating a context with config maps.
|
||||||
|
// +optional
|
||||||
|
configStore {{.reconcilerConfigStore|raw}}
|
||||||
|
|
||||||
// reconciler is the implementation of the business logic of the resource.
|
// reconciler is the implementation of the business logic of the resource.
|
||||||
reconciler Interface
|
reconciler Interface
|
||||||
}
|
}
|
||||||
|
@ -177,21 +189,39 @@ var _ controller.Reconciler = (*reconcilerImpl)(nil)
|
||||||
`
|
`
|
||||||
|
|
||||||
var reconcilerNewReconciler = `
|
var reconcilerNewReconciler = `
|
||||||
func NewReconciler(ctx context.Context, logger *{{.zapSugaredLogger|raw}}, client {{.clientsetInterface|raw}}, lister {{.resourceLister|raw}}, recorder {{.recordEventRecorder|raw}}, r Interface) {{.controllerReconciler|raw}} {
|
func NewReconciler(ctx {{.contextContext|raw}}, logger *{{.zapSugaredLogger|raw}}, client {{.clientsetInterface|raw}}, lister {{.resourceLister|raw}}, recorder {{.recordEventRecorder|raw}}, r Interface, options ...{{.controllerOptions|raw}} ) {{.controllerReconciler|raw}} {
|
||||||
return &reconcilerImpl{
|
// Check the options function input. It should be 0 or 1.
|
||||||
|
if len(options) > 1 {
|
||||||
|
logger.Fatalf("up to one options struct is supported, found %d", len(options))
|
||||||
|
}
|
||||||
|
|
||||||
|
rec := &reconcilerImpl{
|
||||||
Client: client,
|
Client: client,
|
||||||
Lister: lister,
|
Lister: lister,
|
||||||
Recorder: recorder,
|
Recorder: recorder,
|
||||||
reconciler: r,
|
reconciler: r,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, opts := range options {
|
||||||
|
if opts.ConfigStore != nil {
|
||||||
|
rec.configStore = opts.ConfigStore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
var reconcilerImplFactory = `
|
var reconcilerImplFactory = `
|
||||||
// Reconcile implements controller.Reconciler
|
// Reconcile implements controller.Reconciler
|
||||||
func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error {
|
func (r *reconcilerImpl) Reconcile(ctx {{.contextContext|raw}}, key string) error {
|
||||||
logger := {{.loggingFromContext|raw}}(ctx)
|
logger := {{.loggingFromContext|raw}}(ctx)
|
||||||
|
|
||||||
|
// If configStore is set, attach the frozen configuration to the context.
|
||||||
|
if r.configStore != nil {
|
||||||
|
ctx = r.configStore.ToContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
// Convert the namespace/name string into a distinct namespace and name
|
// Convert the namespace/name string into a distinct namespace and name
|
||||||
namespace, name, err := {{.cacheSplitMetaNamespaceKey|raw}}(key)
|
namespace, name, err := {{.cacheSplitMetaNamespaceKey|raw}}(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -199,11 +229,6 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(n3wscott): this is needed for serving.
|
|
||||||
// If our controller has configuration state, we'd "freeze" it and
|
|
||||||
// attach the frozen configuration to the context.
|
|
||||||
// ctx = r.configStore.ToContext(ctx)
|
|
||||||
|
|
||||||
// Get the resource with this namespace/name.
|
// Get the resource with this namespace/name.
|
||||||
original, err := r.Lister.{{.type|apiGroup}}(namespace).Get(name)
|
original, err := r.Lister.{{.type|apiGroup}}(namespace).Get(name)
|
||||||
if {{.apierrsIsNotFound|raw}}(err) {
|
if {{.apierrsIsNotFound|raw}}(err) {
|
||||||
|
@ -218,9 +243,12 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error {
|
||||||
|
|
||||||
var reconcileEvent {{.reconcilerEvent|raw}}
|
var reconcileEvent {{.reconcilerEvent|raw}}
|
||||||
if resource.GetDeletionTimestamp().IsZero() {
|
if resource.GetDeletionTimestamp().IsZero() {
|
||||||
|
// Append the target method to the logger.
|
||||||
|
logger = logger.With(zap.String("targetMethod", "ReconcileKind"))
|
||||||
|
|
||||||
// Set and update the finalizer on resource if r.reconciler
|
// Set and update the finalizer on resource if r.reconciler
|
||||||
// implements Finalizer.
|
// implements Finalizer.
|
||||||
if err := r.setFinalizerIfFinalizer(ctx, resource); err != nil {
|
if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil {
|
||||||
logger.Warnw("Failed to set finalizers", zap.Error(err))
|
logger.Warnw("Failed to set finalizers", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,10 +256,13 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error {
|
||||||
// updates regardless of whether the reconciliation errored out.
|
// updates regardless of whether the reconciliation errored out.
|
||||||
reconcileEvent = r.reconciler.ReconcileKind(ctx, resource)
|
reconcileEvent = r.reconciler.ReconcileKind(ctx, resource)
|
||||||
} else if fin, ok := r.reconciler.(Finalizer); ok {
|
} else if fin, ok := r.reconciler.(Finalizer); ok {
|
||||||
|
// Append the target method to the logger.
|
||||||
|
logger = logger.With(zap.String("targetMethod", "FinalizeKind"))
|
||||||
|
|
||||||
// For finalizing reconcilers, if this resource being marked for deletion
|
// For finalizing reconcilers, if this resource being marked for deletion
|
||||||
// and reconciled cleanly (nil or normal event), remove the finalizer.
|
// and reconciled cleanly (nil or normal event), remove the finalizer.
|
||||||
reconcileEvent = fin.FinalizeKind(ctx, resource)
|
reconcileEvent = fin.FinalizeKind(ctx, resource)
|
||||||
if err := r.clearFinalizer(ctx, resource, reconcileEvent); err != nil {
|
if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil {
|
||||||
logger.Warnw("Failed to clear finalizers", zap.Error(err))
|
logger.Warnw("Failed to clear finalizers", zap.Error(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -253,11 +284,11 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error {
|
||||||
if reconcileEvent != nil {
|
if reconcileEvent != nil {
|
||||||
var event *{{.reconcilerReconcilerEvent|raw}}
|
var event *{{.reconcilerReconcilerEvent|raw}}
|
||||||
if reconciler.EventAs(reconcileEvent, &event) {
|
if reconciler.EventAs(reconcileEvent, &event) {
|
||||||
logger.Infow("ReconcileKind returned an event", zap.Any("event", reconcileEvent))
|
logger.Infow("returned an event", zap.Any("event", reconcileEvent))
|
||||||
r.Recorder.Eventf(resource, event.EventType, event.Reason, event.Format, event.Args...)
|
r.Recorder.Eventf(resource, event.EventType, event.Reason, event.Format, event.Args...)
|
||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
logger.Errorw("ReconcileKind returned an error", zap.Error(reconcileEvent))
|
logger.Errorw("returned an error", zap.Error(reconcileEvent))
|
||||||
r.Recorder.Event(resource, {{.corev1EventTypeWarning|raw}}, "InternalError", reconcileEvent.Error())
|
r.Recorder.Event(resource, {{.corev1EventTypeWarning|raw}}, "InternalError", reconcileEvent.Error())
|
||||||
return reconcileEvent
|
return reconcileEvent
|
||||||
}
|
}
|
||||||
|
@ -294,12 +325,12 @@ var reconcilerFinalizerFactory = `
|
||||||
// updateFinalizersFiltered will update the Finalizers of the resource.
|
// updateFinalizersFiltered will update the Finalizers of the resource.
|
||||||
// TODO: this method could be generic and sync all finalizers. For now it only
|
// TODO: this method could be generic and sync all finalizers. For now it only
|
||||||
// updates defaultFinalizerName.
|
// updates defaultFinalizerName.
|
||||||
func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *{{.type|raw}}) error {
|
func (r *reconcilerImpl) updateFinalizersFiltered(ctx {{.contextContext|raw}}, resource *{{.type|raw}}) (*{{.type|raw}}, error) {
|
||||||
finalizerName := defaultFinalizerName
|
finalizerName := defaultFinalizerName
|
||||||
|
|
||||||
actual, err := r.Lister.{{.type|apiGroup}}(resource.Namespace).Get(resource.Name)
|
actual, err := r.Lister.{{.type|apiGroup}}(resource.Namespace).Get(resource.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return resource, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't modify the informers copy.
|
// Don't modify the informers copy.
|
||||||
|
@ -314,14 +345,14 @@ func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource
|
||||||
if desiredFinalizers.Has(finalizerName) {
|
if desiredFinalizers.Has(finalizerName) {
|
||||||
if existingFinalizers.Has(finalizerName) {
|
if existingFinalizers.Has(finalizerName) {
|
||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
return nil
|
return resource, nil
|
||||||
}
|
}
|
||||||
// Add the finalizer.
|
// Add the finalizer.
|
||||||
finalizers = append(existing.Finalizers, finalizerName)
|
finalizers = append(existing.Finalizers, finalizerName)
|
||||||
} else {
|
} else {
|
||||||
if !existingFinalizers.Has(finalizerName) {
|
if !existingFinalizers.Has(finalizerName) {
|
||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
return nil
|
return resource, nil
|
||||||
}
|
}
|
||||||
// Remove the finalizer.
|
// Remove the finalizer.
|
||||||
existingFinalizers.Delete(finalizerName)
|
existingFinalizers.Delete(finalizerName)
|
||||||
|
@ -337,10 +368,10 @@ func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource
|
||||||
|
|
||||||
patch, err := json.Marshal(mergePatch)
|
patch, err := json.Marshal(mergePatch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return resource, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = r.Client.{{.type|versionedClientset}}().{{.type|apiGroup}}(resource.Namespace).Patch(resource.Name, types.MergePatchType, patch)
|
resource, err = r.Client.{{.type|versionedClientset}}().{{.type|apiGroup}}(resource.Namespace).Patch(resource.Name, types.MergePatchType, patch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.Recorder.Eventf(resource, {{.corev1EventTypeWarning|raw}}, "FinalizerUpdateFailed",
|
r.Recorder.Eventf(resource, {{.corev1EventTypeWarning|raw}}, "FinalizerUpdateFailed",
|
||||||
"Failed to update finalizers for %q: %v", resource.Name, err)
|
"Failed to update finalizers for %q: %v", resource.Name, err)
|
||||||
|
@ -348,12 +379,12 @@ func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource
|
||||||
r.Recorder.Eventf(resource, {{.corev1EventTypeNormal|raw}}, "FinalizerUpdate",
|
r.Recorder.Eventf(resource, {{.corev1EventTypeNormal|raw}}, "FinalizerUpdate",
|
||||||
"Updated %q finalizers", resource.GetName())
|
"Updated %q finalizers", resource.GetName())
|
||||||
}
|
}
|
||||||
return err
|
return resource, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *{{.type|raw}}) error {
|
func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx {{.contextContext|raw}}, resource *{{.type|raw}}) (*{{.type|raw}}, error) {
|
||||||
if _, ok := r.reconciler.(Finalizer); !ok {
|
if _, ok := r.reconciler.(Finalizer); !ok {
|
||||||
return nil
|
return resource, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
finalizers := {{.setsNewString|raw}}(resource.Finalizers...)
|
finalizers := {{.setsNewString|raw}}(resource.Finalizers...)
|
||||||
|
@ -369,12 +400,12 @@ func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *
|
||||||
return r.updateFinalizersFiltered(ctx, resource)
|
return r.updateFinalizersFiltered(ctx, resource)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *{{.type|raw}}, reconcileEvent {{.reconcilerEvent|raw}}) error {
|
func (r *reconcilerImpl) clearFinalizer(ctx {{.contextContext|raw}}, resource *{{.type|raw}}, reconcileEvent {{.reconcilerEvent|raw}}) (*{{.type|raw}}, error) {
|
||||||
if _, ok := r.reconciler.(Finalizer); !ok {
|
if _, ok := r.reconciler.(Finalizer); !ok {
|
||||||
return nil
|
return resource, nil
|
||||||
}
|
}
|
||||||
if resource.GetDeletionTimestamp().IsZero() {
|
if resource.GetDeletionTimestamp().IsZero() {
|
||||||
return nil
|
return resource, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
finalizers := {{.setsNewString|raw}}(resource.Finalizers...)
|
finalizers := {{.setsNewString|raw}}(resource.Finalizers...)
|
||||||
|
@ -382,7 +413,7 @@ func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *{{.type|r
|
||||||
if reconcileEvent != nil {
|
if reconcileEvent != nil {
|
||||||
var event *{{.reconcilerReconcilerEvent|raw}}
|
var event *{{.reconcilerReconcilerEvent|raw}}
|
||||||
if reconciler.EventAs(reconcileEvent, &event) {
|
if reconciler.EventAs(reconcileEvent, &event) {
|
||||||
if event.EventType == v1.EventTypeNormal {
|
if event.EventType == {{.corev1EventTypeNormal|raw}} {
|
||||||
finalizers.Delete(defaultFinalizerName)
|
finalizers.Delete(defaultFinalizerName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,6 +81,10 @@ func (g *reconcilerReconcilerStubGenerator) GenerateType(c *generator.Context, t
|
||||||
Package: "k8s.io/api/core/v1",
|
Package: "k8s.io/api/core/v1",
|
||||||
Name: "EventTypeNormal",
|
Name: "EventTypeNormal",
|
||||||
}),
|
}),
|
||||||
|
"contextContext": c.Universe.Type(types.Name{
|
||||||
|
Package: "context",
|
||||||
|
Name: "Context",
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
sw.Do(reconcilerReconcilerStub, m)
|
sw.Do(reconcilerReconcilerStub, m)
|
||||||
|
@ -110,7 +114,7 @@ var _ {{.reconcilerInterface|raw}} = (*Reconciler)(nil)
|
||||||
|
|
||||||
|
|
||||||
// ReconcileKind implements Interface.ReconcileKind.
|
// ReconcileKind implements Interface.ReconcileKind.
|
||||||
func (r *Reconciler) ReconcileKind(ctx context.Context, o *{{.type|raw}}) {{.reconcilerEvent|raw}} {
|
func (r *Reconciler) ReconcileKind(ctx {{.contextContext|raw}}, o *{{.type|raw}}) {{.reconcilerEvent|raw}} {
|
||||||
o.Status.InitializeConditions()
|
o.Status.InitializeConditions()
|
||||||
|
|
||||||
// TODO: add custom reconciliation logic here.
|
// TODO: add custom reconciliation logic here.
|
||||||
|
@ -121,7 +125,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, o *{{.type|raw}}) {{.rec
|
||||||
|
|
||||||
// Optionally, use FinalizeKind to add finalizers. FinalizeKind will be called
|
// Optionally, use FinalizeKind to add finalizers. FinalizeKind will be called
|
||||||
// when the resource is deleted.
|
// when the resource is deleted.
|
||||||
//func (r *Reconciler) FinalizeKind(ctx context.Context, o *{{.type|raw}}) {{.reconcilerEvent|raw}} {
|
//func (r *Reconciler) FinalizeKind(ctx {{.contextContext|raw}}, o *{{.type|raw}}) {{.reconcilerEvent|raw}} {
|
||||||
// // TODO: add custom finalization logic here.
|
// // TODO: add custom finalization logic here.
|
||||||
// return nil
|
// return nil
|
||||||
//}
|
//}
|
||||||
|
|
|
@ -86,15 +86,48 @@ func HandleAll(h func(interface{})) cache.ResourceEventHandler {
|
||||||
// Filter makes it simple to create FilterFunc's for use with
|
// Filter makes it simple to create FilterFunc's for use with
|
||||||
// cache.FilteringResourceEventHandler that filter based on the
|
// cache.FilteringResourceEventHandler that filter based on the
|
||||||
// schema.GroupVersionKind of the controlling resources.
|
// schema.GroupVersionKind of the controlling resources.
|
||||||
|
//
|
||||||
|
// Deprecated: Use FilterGroupVersionKind or FilterGroupKind instead
|
||||||
func Filter(gvk schema.GroupVersionKind) func(obj interface{}) bool {
|
func Filter(gvk schema.GroupVersionKind) func(obj interface{}) bool {
|
||||||
|
return FilterGroupVersionKind(gvk)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilterGroupVersionKind makes it simple to create FilterFunc's for use with
|
||||||
|
// cache.FilteringResourceEventHandler that filter based on the
|
||||||
|
// schema.GroupVersionKind of the controlling resources.
|
||||||
|
func FilterGroupVersionKind(gvk schema.GroupVersionKind) func(obj interface{}) bool {
|
||||||
return func(obj interface{}) bool {
|
return func(obj interface{}) bool {
|
||||||
if object, ok := obj.(metav1.Object); ok {
|
object, ok := obj.(metav1.Object)
|
||||||
owner := metav1.GetControllerOf(object)
|
if !ok {
|
||||||
return owner != nil &&
|
return false
|
||||||
owner.APIVersion == gvk.GroupVersion().String() &&
|
|
||||||
owner.Kind == gvk.Kind
|
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
|
owner := metav1.GetControllerOf(object)
|
||||||
|
return owner != nil &&
|
||||||
|
owner.APIVersion == gvk.GroupVersion().String() &&
|
||||||
|
owner.Kind == gvk.Kind
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilterGroupKind makes it simple to create FilterFunc's for use with
|
||||||
|
// cache.FilteringResourceEventHandler that filter based on the
|
||||||
|
// schema.GroupKind of the controlling resources.
|
||||||
|
func FilterGroupKind(gk schema.GroupKind) func(obj interface{}) bool {
|
||||||
|
return func(obj interface{}) bool {
|
||||||
|
object, ok := obj.(metav1.Object)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
owner := metav1.GetControllerOf(object)
|
||||||
|
if owner == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
ownerGV, err := schema.ParseGroupVersion(owner.APIVersion)
|
||||||
|
return err == nil &&
|
||||||
|
ownerGV.Group == gk.Group &&
|
||||||
|
owner.Kind == gk.Kind
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 The Knative Authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package controller
|
||||||
|
|
||||||
|
import "knative.dev/pkg/reconciler"
|
||||||
|
|
||||||
|
// Options is additional resources a Controller might want to use depending
|
||||||
|
// on implementation.
|
||||||
|
type Options struct {
|
||||||
|
// ConfigStore is used to attach the frozen configuration to the context.
|
||||||
|
ConfigStore reconciler.ConfigStore
|
||||||
|
}
|
||||||
|
|
||||||
|
// OptionsFn is a callback method signature that accepts an Impl and returns
|
||||||
|
// Options. Used for controllers that need access to the members of Options but
|
||||||
|
// to build Options, integrators need an Impl.
|
||||||
|
type OptionsFn func(impl *Impl) Options
|
|
@ -63,9 +63,9 @@ impl := controller.NewImpl(c, logger, "NameOfController")
|
||||||
becomes
|
becomes
|
||||||
|
|
||||||
```go
|
```go
|
||||||
reconciler "knative.dev/<repo>/pkg/client/injection/reconciler/<clientgroup>/<version>/<resource>"
|
kindreconciler "knative.dev/<repo>/pkg/client/injection/reconciler/<clientgroup>/<version>/<resource>"
|
||||||
...
|
...
|
||||||
impl := reconciler.NewImpl(ctx, c)
|
impl := kindreconciler.NewImpl(ctx, c)
|
||||||
```
|
```
|
||||||
|
|
||||||
See
|
See
|
||||||
|
@ -359,6 +359,35 @@ Future features to be considered:
|
||||||
- Adjust `+genreconciler` to allow for generated reconcilers to be made without
|
- Adjust `+genreconciler` to allow for generated reconcilers to be made without
|
||||||
annotating the type struct.
|
annotating the type struct.
|
||||||
|
|
||||||
|
### ConfigStore
|
||||||
|
|
||||||
|
Config store is used to decorate the context with a snapshot of configmaps to be
|
||||||
|
used in a reconciler method.
|
||||||
|
|
||||||
|
To add this feature to the generated reconciler, it will have to be passed in on
|
||||||
|
`reconciler<kind>.NewImpl` like so:
|
||||||
|
|
||||||
|
```go
|
||||||
|
kindreconciler "knative.dev/<repo>/pkg/client/injection/reconciler/<clientgroup>/<version>/<resource>"
|
||||||
|
...
|
||||||
|
impl := kindreconciler.NewImpl(ctx, c, func(impl *controller.Impl) controller.Options {
|
||||||
|
// Setup options that require access to a controller.Impl.
|
||||||
|
configsToResync := []interface{}{
|
||||||
|
&some.Config{},
|
||||||
|
}
|
||||||
|
resyncOnConfigChange := configmap.TypeFilter(configsToResync...)(func(string, interface{}) {
|
||||||
|
impl.FilteredGlobalResync(myFilterFunc, kindInformer.Informer())
|
||||||
|
})
|
||||||
|
configStore := config.NewStore(c.Logger.Named("config-store"), resyncOnConfigChange)
|
||||||
|
configStore.WatchConfigs(cmw)
|
||||||
|
|
||||||
|
// Return the controller options.
|
||||||
|
return controller.Options{
|
||||||
|
ConfigStore: configStore,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
### Artifacts
|
### Artifacts
|
||||||
|
|
||||||
The artifacts are targeted to the configured `client/injection` directory:
|
The artifacts are targeted to the configured `client/injection` directory:
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 The Knative Authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Veroute.on 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package reconciler
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
// ConfigStore is used to attach the frozen configuration to the context.
|
||||||
|
type ConfigStore interface {
|
||||||
|
// ConfigStore is used to attach the frozen configuration to the context.
|
||||||
|
ToContext(ctx context.Context) context.Context
|
||||||
|
}
|
|
@ -26,8 +26,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/markbates/inflect"
|
"github.com/markbates/inflect"
|
||||||
"github.com/mattbaird/jsonpatch"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
jsonpatch "gomodules.xyz/jsonpatch/v2"
|
||||||
admissionv1beta1 "k8s.io/api/admission/v1beta1"
|
admissionv1beta1 "k8s.io/api/admission/v1beta1"
|
||||||
admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1"
|
admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
|
|
@ -24,7 +24,7 @@ import (
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
"github.com/google/go-cmp/cmp/cmpopts"
|
"github.com/google/go-cmp/cmp/cmpopts"
|
||||||
"github.com/mattbaird/jsonpatch"
|
jsonpatch "gomodules.xyz/jsonpatch/v2"
|
||||||
admissionv1beta1 "k8s.io/api/admission/v1beta1"
|
admissionv1beta1 "k8s.io/api/admission/v1beta1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"knative.dev/pkg/system"
|
"knative.dev/pkg/system"
|
||||||
|
|
|
@ -231,9 +231,12 @@ function create_test_cluster() {
|
||||||
[[ -n "${GCP_PROJECT}" ]] && test_cmd_args+=" --gcp-project ${GCP_PROJECT}"
|
[[ -n "${GCP_PROJECT}" ]] && test_cmd_args+=" --gcp-project ${GCP_PROJECT}"
|
||||||
[[ -n "${E2E_SCRIPT_CUSTOM_FLAGS[@]}" ]] && test_cmd_args+=" ${E2E_SCRIPT_CUSTOM_FLAGS[@]}"
|
[[ -n "${E2E_SCRIPT_CUSTOM_FLAGS[@]}" ]] && test_cmd_args+=" ${E2E_SCRIPT_CUSTOM_FLAGS[@]}"
|
||||||
local extra_flags=()
|
local extra_flags=()
|
||||||
if (( IS_BOSKOS )); then # Add arbitrary duration, wait for Boskos projects acquisition before error out
|
if (( IS_BOSKOS )); then
|
||||||
|
# Add arbitrary duration, wait for Boskos projects acquisition before error out
|
||||||
extra_flags+=(--boskos-wait-duration=20m)
|
extra_flags+=(--boskos-wait-duration=20m)
|
||||||
else # Only let kubetest tear down the cluster if not using Boskos, it's done by Janitor if using Boskos
|
elif (( ! SKIP_TEARDOWNS )); then
|
||||||
|
# Only let kubetest tear down the cluster if not using Boskos and teardowns are not expected to be skipped,
|
||||||
|
# it's done by Janitor if using Boskos
|
||||||
extra_flags+=(--down)
|
extra_flags+=(--down)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue