From b1361e05f81cd888ae2bde9a5cf61133efe2a5a0 Mon Sep 17 00:00:00 2001 From: Dmitry Ukov Date: Tue, 17 Dec 2019 12:26:07 +0400 Subject: [PATCH] Implement document plugin loader Loader associated with Unknown type of a transformer kustomize plugin and considered 'builtin'. Kustomize plugin system executes Config and Transform method of builtin plugins. Therefore appropriate methods of the document plugin loaders are executed as well. Main goal for airship document plugin loaded is to determine desired aitship plugin based on Kind field and execute its Config or Transform methods Change-Id: Ic26a880570491ac3a59f2357ed455a2a7362387b --- pkg/document/bundle.go | 7 +++ pkg/document/plugins/errors.go | 28 +++++++++ pkg/document/plugins/loader.go | 60 +++++++++++++++++++ pkg/document/plugins/loader_test.go | 33 ++++++++++ .../testdata/unknownplugin/dummyplugin.yaml | 4 ++ .../testdata/unknownplugin/kustomization.yaml | 2 + 6 files changed, 134 insertions(+) create mode 100644 pkg/document/plugins/errors.go create mode 100644 pkg/document/plugins/loader.go create mode 100644 pkg/document/plugins/loader_test.go create mode 100644 pkg/document/plugins/testdata/unknownplugin/dummyplugin.yaml create mode 100644 pkg/document/plugins/testdata/unknownplugin/kustomization.yaml diff --git a/pkg/document/bundle.go b/pkg/document/bundle.go index 17855d829..a6aa4557a 100644 --- a/pkg/document/bundle.go +++ b/pkg/document/bundle.go @@ -16,10 +16,17 @@ import ( "sigs.k8s.io/kustomize/v3/pkg/target" "sigs.k8s.io/kustomize/v3/pkg/types" + docplugins "opendev.org/airship/airshipctl/pkg/document/plugins" "opendev.org/airship/airshipctl/pkg/log" utilyaml "opendev.org/airship/airshipctl/pkg/util/yaml" ) +func init() { + // NOTE (dukov) This is sort of a hack but it's the only way to add an + // external 'builtin' plugin to Kustomize + plugins.TransformerFactories[plugins.Unknown] = docplugins.NewTransformerLoader +} + // KustomizeBuildOptions contain the options for running a Kustomize build on a bundle type KustomizeBuildOptions struct { KustomizationPath string diff --git a/pkg/document/plugins/errors.go b/pkg/document/plugins/errors.go new file mode 100644 index 000000000..0c9f5cd69 --- /dev/null +++ b/pkg/document/plugins/errors.go @@ -0,0 +1,28 @@ +/* +Copyright 2014 The Kubernetes 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 + + 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 plugins + +import "fmt" + +// ErrUnknownPlugin raised for unregistered plugins +type ErrUnknownPlugin struct { + Kind string +} + +func (e ErrUnknownPlugin) Error() string { + return fmt.Sprintf("Unknown airship plugin with Kind: %s", e.Kind) +} diff --git a/pkg/document/plugins/loader.go b/pkg/document/plugins/loader.go new file mode 100644 index 000000000..8eec1b77f --- /dev/null +++ b/pkg/document/plugins/loader.go @@ -0,0 +1,60 @@ +/* +Copyright 2014 The Kubernetes 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 + + 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 plugins + +import ( + "sigs.k8s.io/kustomize/v3/pkg/ifc" + "sigs.k8s.io/kustomize/v3/pkg/resid" + "sigs.k8s.io/kustomize/v3/pkg/resmap" + "sigs.k8s.io/yaml" +) + +// PluginRegistry map of plugin kinds to plugin instance +var PluginRegistry = make(map[string]resmap.TransformerPlugin) + +// TransformerLoader airship document plugin loader. Loads external +// Kustomize plugins as builtin +type TransformerLoader struct { + resid.ResId +} + +// Config reads plugin configuration structure +func (l *TransformerLoader) Config( + ldr ifc.Loader, rf *resmap.Factory, c []byte) error { + if err := yaml.Unmarshal(c, l); err != nil { + return err + } + airshipPlugin, found := PluginRegistry[l.Kind] + if !found { + return ErrUnknownPlugin{Kind: l.Kind} + } + return airshipPlugin.Config(ldr, rf, c) +} + +// Transform executes Transform method of an external plugin +func (l *TransformerLoader) Transform(m resmap.ResMap) error { + airshipPlugin, found := PluginRegistry[l.Kind] + if !found { + return ErrUnknownPlugin{Kind: l.Kind} + } + return airshipPlugin.Transform(m) +} + +// NewTransformerLoader returns plugin loader instance +func NewTransformerLoader() resmap.TransformerPlugin { + return &TransformerLoader{} +} diff --git a/pkg/document/plugins/loader_test.go b/pkg/document/plugins/loader_test.go new file mode 100644 index 000000000..848dbb77f --- /dev/null +++ b/pkg/document/plugins/loader_test.go @@ -0,0 +1,33 @@ +/* +Copyright 2014 The Kubernetes 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 + + 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 plugins_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "opendev.org/airship/airshipctl/pkg/document" + "opendev.org/airship/airshipctl/testutil" +) + +func TestLoaderConfig(t *testing.T) { + t.Run("Try load non-existent plugin", func(t *testing.T) { + _, err := document.NewBundle(testutil.SetupTestFs(t, "testdata/unknownplugin"), "/", "/") + assert.Error(t, err) + }) +} diff --git a/pkg/document/plugins/testdata/unknownplugin/dummyplugin.yaml b/pkg/document/plugins/testdata/unknownplugin/dummyplugin.yaml new file mode 100644 index 000000000..e1f830ba8 --- /dev/null +++ b/pkg/document/plugins/testdata/unknownplugin/dummyplugin.yaml @@ -0,0 +1,4 @@ +apiVersion: builtin +kind: SomeKind +metadata: + name: notImportantHere \ No newline at end of file diff --git a/pkg/document/plugins/testdata/unknownplugin/kustomization.yaml b/pkg/document/plugins/testdata/unknownplugin/kustomization.yaml new file mode 100644 index 000000000..fc03de19f --- /dev/null +++ b/pkg/document/plugins/testdata/unknownplugin/kustomization.yaml @@ -0,0 +1,2 @@ +transformers: + - dummyplugin.yaml \ No newline at end of file