Merge "Introduce document plugin subcommand"
This commit is contained in:
commit
0cf53db3b6
@ -29,6 +29,7 @@ func NewDocumentCommand(rootSettings *environment.AirshipCTLSettings) *cobra.Com
|
||||
|
||||
documentRootCmd.AddCommand(NewDocumentPullCommand(rootSettings))
|
||||
documentRootCmd.AddCommand(NewRenderCommand(rootSettings))
|
||||
documentRootCmd.AddCommand(NewDocumentPluginCommand(rootSettings))
|
||||
|
||||
return documentRootCmd
|
||||
}
|
||||
|
66
cmd/document/plugin.go
Normal file
66
cmd/document/plugin.go
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
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 document
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/document/plugin"
|
||||
"opendev.org/airship/airshipctl/pkg/environment"
|
||||
)
|
||||
|
||||
var longDescription = `Subcommand reads configuration file CONFIG passed as
|
||||
a first argument and determines a particular plugin to execute. Additional
|
||||
arguments may be passed to this sub-command abd can be used by the
|
||||
particular plugin. CONFIG file must be structured as kubernetes
|
||||
manifest (i.e. resource) and must have 'apiVersion' and 'kind' keys.
|
||||
|
||||
Example:
|
||||
$ cat /tmp/generator.yaml
|
||||
---
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
kind: BareMetalHostGenerator
|
||||
spec:
|
||||
hostList:
|
||||
- mac: 00:aa:bb:cc:dd
|
||||
powerAddress: redfish+http://1.2.3.4/
|
||||
|
||||
$ airshipctl document plugin /tmp/generator.yaml
|
||||
|
||||
subcommand will try to identify appropriate plugin using apiVersion and
|
||||
kind keys (a.k.a group, version, kind) as an identifier. If appropriate
|
||||
plugin was not found command returns an error.
|
||||
`
|
||||
|
||||
// NewDocumentPluginCommand creates a new command which can act as kustomize
|
||||
// exec plugin.
|
||||
func NewDocumentPluginCommand(rootSetting *environment.AirshipCTLSettings) *cobra.Command {
|
||||
pluginCmd := &cobra.Command{
|
||||
Use: "plugin CONFIG [ARGS]",
|
||||
Short: "used as kustomize exec plugin",
|
||||
Long: longDescription,
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cfg, err := ioutil.ReadFile(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return plugin.ConfigureAndRun(rootSetting, cfg, cmd.InOrStdin(), cmd.OutOrStdout())
|
||||
},
|
||||
}
|
||||
return pluginCmd
|
||||
}
|
48
cmd/document/plugin_test.go
Normal file
48
cmd/document/plugin_test.go
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
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 document
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"opendev.org/airship/airshipctl/testutil"
|
||||
)
|
||||
|
||||
func TestPlugin(t *testing.T) {
|
||||
cmdTests := []*testutil.CmdTest{
|
||||
{
|
||||
Name: "document-plugin-cmd-with-help",
|
||||
CmdLine: "--help",
|
||||
Cmd: NewDocumentPluginCommand(nil),
|
||||
},
|
||||
{
|
||||
Name: "document-plugin-cmd-with-empty-args",
|
||||
CmdLine: "",
|
||||
Error: fmt.Errorf("requires at least 1 arg(s), only received 0"),
|
||||
Cmd: NewDocumentPluginCommand(nil),
|
||||
},
|
||||
{
|
||||
Name: "document-plugin-cmd-with-nonexistent-config",
|
||||
CmdLine: "/some/random/path.yaml",
|
||||
Error: fmt.Errorf("open /some/random/path.yaml: no such file or directory"),
|
||||
Cmd: NewDocumentPluginCommand(nil),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range cmdTests {
|
||||
testutil.RunTest(t, tt)
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ Usage:
|
||||
|
||||
Available Commands:
|
||||
help Help about any command
|
||||
plugin used as kustomize exec plugin
|
||||
pull pulls documents from remote git repository
|
||||
render Render documents from model
|
||||
|
||||
|
7
cmd/document/testdata/TestPluginGoldenOutput/document-plugin-cmd-with-empty-args.golden
vendored
Normal file
7
cmd/document/testdata/TestPluginGoldenOutput/document-plugin-cmd-with-empty-args.golden
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
Error: requires at least 1 arg(s), only received 0
|
||||
Usage:
|
||||
plugin CONFIG [ARGS] [flags]
|
||||
|
||||
Flags:
|
||||
-h, --help help for plugin
|
||||
|
27
cmd/document/testdata/TestPluginGoldenOutput/document-plugin-cmd-with-help.golden
vendored
Normal file
27
cmd/document/testdata/TestPluginGoldenOutput/document-plugin-cmd-with-help.golden
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
Subcommand reads configuration file CONFIG passed as
|
||||
a first argument and determines a particular plugin to execute. Additional
|
||||
arguments may be passed to this sub-command abd can be used by the
|
||||
particular plugin. CONFIG file must be structured as kubernetes
|
||||
manifest (i.e. resource) and must have 'apiVersion' and 'kind' keys.
|
||||
|
||||
Example:
|
||||
$ cat /tmp/generator.yaml
|
||||
---
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
kind: BareMetalHostGenerator
|
||||
spec:
|
||||
hostList:
|
||||
- mac: 00:aa:bb:cc:dd
|
||||
powerAddress: redfish+http://1.2.3.4/
|
||||
|
||||
$ airshipctl document plugin /tmp/generator.yaml
|
||||
|
||||
subcommand will try to identify appropriate plugin using apiVersion and
|
||||
kind keys (a.k.a group, version, kind) as an identifier. If appropriate
|
||||
plugin was not found command returns an error.
|
||||
|
||||
Usage:
|
||||
plugin CONFIG [ARGS] [flags]
|
||||
|
||||
Flags:
|
||||
-h, --help help for plugin
|
@ -0,0 +1,7 @@
|
||||
Error: open /some/random/path.yaml: no such file or directory
|
||||
Usage:
|
||||
plugin CONFIG [ARGS] [flags]
|
||||
|
||||
Flags:
|
||||
-h, --help help for plugin
|
||||
|
@ -18,7 +18,6 @@ import (
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/konfig"
|
||||
"sigs.k8s.io/kustomize/api/krusty"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
@ -84,8 +83,11 @@ func NewBundle(fSys FileSystem, kustomizePath string) (Bundle, error) {
|
||||
var o = krusty.Options{
|
||||
DoLegacyResourceSort: true, // Default and what we want
|
||||
LoadRestrictions: options.LoadRestrictions,
|
||||
DoPrune: false, // Default
|
||||
PluginConfig: konfig.DisabledPluginConfig(), // Default
|
||||
DoPrune: false, // Default
|
||||
PluginConfig: &types.PluginConfig{
|
||||
AbsPluginHome: kustomizePath,
|
||||
PluginRestrictions: types.PluginRestrictionsNone,
|
||||
},
|
||||
}
|
||||
|
||||
kustomizer := krusty.MakeKustomizer(fSys, &o)
|
||||
|
32
pkg/document/plugin/errors.go
Normal file
32
pkg/document/plugin/errors.go
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
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 plugin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// ErrPluginNotFound is returned if a plugin was not found in the plugin
|
||||
// registry
|
||||
type ErrPluginNotFound struct {
|
||||
//PluginID group, version and kind plugin identifier
|
||||
PluginID schema.GroupVersionKind
|
||||
}
|
||||
|
||||
func (e ErrPluginNotFound) Error() string {
|
||||
return fmt.Sprintf("plugin identified by %s was not found", e.PluginID.String())
|
||||
}
|
50
pkg/document/plugin/run.go
Normal file
50
pkg/document/plugin/run.go
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
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 plugin
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/document/plugin/types"
|
||||
"opendev.org/airship/airshipctl/pkg/environment"
|
||||
)
|
||||
|
||||
// Registry contains factory functions for the available plugins
|
||||
var Registry = make(map[schema.GroupVersionKind]types.Factory)
|
||||
|
||||
// ConfigureAndRun executes particular plugin based on group, version, kind
|
||||
// which have been specified in configuration file. Config file should be
|
||||
// supplied as a first element of args slice
|
||||
func ConfigureAndRun(settings *environment.AirshipCTLSettings, pluginCfg []byte, in io.Reader, out io.Writer) error {
|
||||
var cfg unstructured.Unstructured
|
||||
if err := yaml.Unmarshal(pluginCfg, &cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
pluginFactory, ok := Registry[cfg.GroupVersionKind()]
|
||||
if !ok {
|
||||
return ErrPluginNotFound{PluginID: cfg.GroupVersionKind()}
|
||||
}
|
||||
|
||||
plugin, err := pluginFactory(settings, pluginCfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return plugin.Run(in, out)
|
||||
}
|
61
pkg/document/plugin/run_test.go
Normal file
61
pkg/document/plugin/run_test.go
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
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 plugin_test
|
||||
|
||||
import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/document/plugin"
|
||||
"opendev.org/airship/airshipctl/pkg/environment"
|
||||
)
|
||||
|
||||
func TestConfigureAndRun(t *testing.T) {
|
||||
testCases := []struct {
|
||||
pluginCfg []byte
|
||||
settings *environment.AirshipCTLSettings
|
||||
expectedError string
|
||||
in io.Reader
|
||||
out io.Writer
|
||||
}{
|
||||
{
|
||||
pluginCfg: []byte(""),
|
||||
expectedError: "plugin identified by /, Kind= was not found",
|
||||
},
|
||||
{
|
||||
pluginCfg: []byte(`---
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
kind: UnknownPlugin
|
||||
spec:
|
||||
someField: someValue`),
|
||||
expectedError: "plugin identified by airshipit.org/v1alpha1, Kind=UnknownPlugin was not found",
|
||||
},
|
||||
{
|
||||
pluginCfg: []byte(`---
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
kind: BareMetalGenereator
|
||||
spec: -
|
||||
someField: someValu`),
|
||||
expectedError: "error converting YAML to JSON: yaml: line 4: block sequence entries are not allowed in this context",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
err := plugin.ConfigureAndRun(tc.settings, tc.pluginCfg, tc.in, tc.out)
|
||||
assert.EqualError(t, err, tc.expectedError)
|
||||
}
|
||||
}
|
30
pkg/document/plugin/types/plugin.go
Normal file
30
pkg/document/plugin/types/plugin.go
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
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 types
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/environment"
|
||||
)
|
||||
|
||||
// Plugin interface for airship document plugins
|
||||
type Plugin interface {
|
||||
Run(io.Reader, io.Writer) error
|
||||
}
|
||||
|
||||
// Factory function for plugins. Functions of such type are used in the plugin
|
||||
// registry to instantiate a plugin object
|
||||
type Factory func(*environment.AirshipCTLSettings, []byte) (Plugin, error)
|
Loading…
x
Reference in New Issue
Block a user