Unverified Commit c15cffba authored by Bryan Liles's avatar Bryan Liles Committed by GitHub
Browse files

Merge pull request #817 from bryanl/747-list-environment-parameters

Allow showing only env set parameters
parents 5b4917a2 49a682d5
......@@ -46,6 +46,7 @@ ks param list guestbook --env=dev
-h, --help help for list
--module string Specify module to list parameters for
-o, --output string Output format. Valid options: table|json
--without-modules Exclude module defaults
```
### Options inherited from parent commands
......
......@@ -224,6 +224,27 @@ var _ = Describe("ks param", func() {
Expect(got).To(Equal(expected))
})
})
Describe("at the environment level without modules", func() {
BeforeEach(func() {
a.generateDeployedService()
a.paramSet("guestbook-ui", "replicas", "3", "--env", "default")
listParams = []string{"param", "list", "-o", "json", "--env", "default", "--without-modules"}
})
It("should exit with 0", func() {
assertExitStatus(listOutput, 0)
})
It("lists the params", func() {
tr := loadTableResponse(listOutput.stdout)
got := tr.paramList()
expected := setGuestBookRow([]paramListRow{}, "replicas", "3")
Expect(got).To(Equal(expected))
})
})
})
Describe("set", func() {
......
......@@ -114,6 +114,8 @@ const (
OptionUnset = "unset"
// OptionURI is uri option. Used for setting registry URI.
OptionURI = "URI"
// OptionWithoutModules is without modules option.
OptionWithoutModules = "without-modules"
// OptionValue is value option.
OptionValue = "value"
// OptionVersion is version option.
......
......@@ -54,12 +54,13 @@ type ParamList struct {
componentName string
envName string
outputType string
withoutModules bool
out io.Writer
findModuleFn findModuleFn
modulesFn func() ([]component.Module, error)
envParametersFn func(string) (string, error)
envParametersFn func(moduleName string, inherited bool) (string, error)
lister paramsLister
}
......@@ -73,6 +74,7 @@ func NewParamList(m map[string]interface{}) (*ParamList, error) {
componentName: ol.LoadOptionalString(OptionComponentName),
envName: ol.LoadOptionalString(OptionEnvName),
outputType: ol.LoadOptionalString(OptionOutput),
withoutModules: ol.LoadOptionalBool(OptionWithoutModules),
out: os.Stdout,
findModuleFn: component.GetModule,
......@@ -142,7 +144,7 @@ func (pl *ParamList) handleEnvParams() error {
var entries []params.Entry
for _, m := range modules {
source, err := pl.envParametersFn(m.Name())
source, err := pl.envParametersFn(m.Name(), !pl.withoutModules)
if err != nil {
return err
}
......
......@@ -53,6 +53,10 @@ func TestParamList(t *testing.T) {
},
}
fakeEnvParametersFn := func(string, bool) (string, error) {
return "{}", nil
}
withApp(t, func(appMock *amocks.App) {
ec := &app.EnvironmentConfig{}
appMock.On("Environment", "envName").Return(ec, nil)
......@@ -61,6 +65,7 @@ func TestParamList(t *testing.T) {
name string
in map[string]interface{}
findModuleFn func(t *testing.T) findModuleFn
envParametersFn func(string, bool) (string, error)
modulesFn func() ([]component.Module, error)
lister paramsLister
outputFile string
......@@ -126,6 +131,24 @@ func TestParamList(t *testing.T) {
lister: fakeLister,
outputFile: filepath.Join("param", "list", "env.txt"),
},
{
name: "env without modules",
in: map[string]interface{}{
OptionApp: appMock,
OptionEnvName: "envName",
OptionWithoutModules: true,
},
modulesFn: func() ([]component.Module, error) {
module.On("Name").Return("/")
return []component.Module{module}, nil
},
lister: fakeLister,
outputFile: filepath.Join("param", "list", "env.txt"),
envParametersFn: func(envName string, inherited bool) (string, error) {
assert.False(t, inherited, "should not request inherited parameters")
return "{}", nil
},
},
{
name: "invalid output type",
in: map[string]interface{}{
......@@ -160,10 +183,13 @@ func TestParamList(t *testing.T) {
a.modulesFn = tc.modulesFn
}
a.envParametersFn = func(string) (string, error) {
return "{}", nil
envParametersFn := tc.envParametersFn
if envParametersFn == nil {
envParametersFn = fakeEnvParametersFn
}
a.envParametersFn = envParametersFn
var buf bytes.Buffer
a.out = &buf
......
......@@ -53,6 +53,7 @@ const (
flagUnset = "unset"
flagVerbose = "verbose"
flagVersion = "version"
flagWithoutModules = "without-modules"
shortComponent = "c"
shortFilename = "f"
......
......@@ -26,6 +26,7 @@ import (
const (
vParamListOutput = "param-list-output"
vParamListWithoutModules = "param-without-modules"
)
var (
......@@ -89,6 +90,7 @@ func newParamListCmd(a app.App) *cobra.Command {
actions.OptionEnvName: env,
actions.OptionModule: module,
actions.OptionOutput: viper.GetString(vParamListOutput),
actions.OptionWithoutModules: viper.GetBool(vParamListWithoutModules),
}
return runAction(actionParamList, m)
......@@ -99,6 +101,9 @@ func newParamListCmd(a app.App) *cobra.Command {
paramListCmd.PersistentFlags().String(flagEnv, "", "Specify environment to list parameters for")
paramListCmd.Flags().String(flagModule, "", "Specify module to list parameters for")
paramListCmd.Flags().Bool(flagWithoutModules, false, "Exclude module defaults")
viper.BindPFlag(vParamListWithoutModules, paramListCmd.Flags().Lookup(flagWithoutModules))
return paramListCmd
}
......@@ -33,6 +33,7 @@ func Test_paramListCmd(t *testing.T) {
actions.OptionModule: "",
actions.OptionComponentName: "",
actions.OptionOutput: "",
actions.OptionWithoutModules: false,
},
},
{
......@@ -45,6 +46,7 @@ func Test_paramListCmd(t *testing.T) {
actions.OptionModule: "",
actions.OptionComponentName: "",
actions.OptionOutput: "json",
actions.OptionWithoutModules: false,
},
},
{
......@@ -57,6 +59,7 @@ func Test_paramListCmd(t *testing.T) {
actions.OptionModule: "",
actions.OptionComponentName: "component",
actions.OptionOutput: "",
actions.OptionWithoutModules: false,
},
},
{
......@@ -69,6 +72,7 @@ func Test_paramListCmd(t *testing.T) {
actions.OptionModule: "module",
actions.OptionComponentName: "",
actions.OptionOutput: "",
actions.OptionWithoutModules: false,
},
},
{
......@@ -81,6 +85,20 @@ func Test_paramListCmd(t *testing.T) {
actions.OptionModule: "",
actions.OptionComponentName: "",
actions.OptionOutput: "",
actions.OptionWithoutModules: false,
},
},
{
name: "env without modules",
args: []string{"param", "list", "--env", "env", "--without-modules"},
action: actionParamList,
expected: map[string]interface{}{
actions.OptionApp: nil,
actions.OptionEnvName: "env",
actions.OptionModule: "",
actions.OptionComponentName: "",
actions.OptionOutput: "",
actions.OptionWithoutModules: true,
},
},
}
......
......@@ -18,6 +18,7 @@ package pipeline
import (
"bytes"
"encoding/json"
"fmt"
"io"
"path/filepath"
"regexp"
......@@ -58,6 +59,7 @@ type Pipeline struct {
buildObjectsFn func(*Pipeline, []string) ([]*unstructured.Unstructured, error)
evaluateEnvFn func(a app.App, envName, components, paramsStr string, opts ...jsonnet.VMOpt) (string, error)
evaluateEnvParamsFn func(a app.App, sourcePath, paramsStr, envName, moduleName string) (string, error)
stubModuleFn func(m component.Module) (string, error)
}
// New creates an instance of Pipeline.
......@@ -70,6 +72,7 @@ func New(ksApp app.App, envName string, opts ...Opt) *Pipeline {
buildObjectsFn: buildObjects,
evaluateEnvFn: env.Evaluate,
evaluateEnvParamsFn: params.EvaluateEnv,
stubModuleFn: stubModule,
}
for _, opt := range opts {
......@@ -85,15 +88,15 @@ func (p *Pipeline) Modules() ([]component.Module, error) {
}
// EnvParameters creates parameters for a namespace given an environment.
func (p *Pipeline) EnvParameters(moduleName string) (string, error) {
func (p *Pipeline) EnvParameters(moduleName string, inherited bool) (string, error) {
module, err := p.cm.Module(p.app, moduleName)
if err != nil {
return "", errors.Wrapf(err, "load module %s", moduleName)
}
paramsStr, err := module.ResolvedParams(p.envName)
paramsStr, err := p.moduleParams(module, inherited)
if err != nil {
return "", errors.Wrapf(err, "resolve params for %s", moduleName)
return "", err
}
data, err := p.app.EnvironmentParams(p.envName)
......@@ -119,6 +122,45 @@ func (p *Pipeline) EnvParameters(moduleName string) (string, error) {
return vm.EvaluateSnippet("snippet", string(envParams))
}
func (p *Pipeline) moduleParams(module component.Module, inherited bool) (string, error) {
if !inherited {
return stubModule(module)
}
paramsStr, err := module.ResolvedParams(p.envName)
if err != nil {
return "", errors.Wrapf(err, "resolve params for %s", module.Name())
}
fmt.Println(paramsStr)
return paramsStr, nil
}
func stubModule(module component.Module) (string, error) {
componentsObject := map[string]interface{}{}
components, err := module.Components()
if err != nil {
return "", errors.Wrap(err, "loading module components")
}
for _, c := range components {
componentsObject[c.Name(true)] = make(map[string]interface{})
}
m := map[string]interface{}{
"components": componentsObject,
}
data, err := json.Marshal(&m)
if err != nil {
return "", err
}
return string(data), nil
}
// Components returns the components that belong to this pipeline.
func (p *Pipeline) Components(filter []string) ([]component.Component, error) {
modules, err := p.Modules()
......
......@@ -27,6 +27,8 @@ import (
cmocks "github.com/ksonnet/ksonnet/pkg/component/mocks"
"github.com/ksonnet/ksonnet/pkg/metadata"
"github.com/ksonnet/ksonnet/pkg/util/jsonnet"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
......@@ -56,7 +58,31 @@ func TestPipeline_EnvParameters(t *testing.T) {
env := &app.EnvironmentConfig{Path: "default"}
a.On("Environment", "default").Return(env, nil)
got, err := p.EnvParameters("/")
got, err := p.EnvParameters("/", true)
require.NoError(t, err)
require.Equal(t, "{ }\n", got)
})
}
func TestPipeline_EnvParameters_inherited(t *testing.T) {
withPipeline(t, func(p *Pipeline, m *cmocks.Manager, a *appmocks.App) {
module := &cmocks.Module{}
module.On("ResolvedParams", "default").Return("{}", nil)
c := &cmocks.Component{}
c.On("Name", true).Return("app")
module.On("Components").Return([]component.Component{c}, nil)
namespaces := []component.Module{module}
m.On("Modules", p.app, "default").Return(namespaces, nil)
m.On("Module", p.app, "/").Return(module, nil)
a.On("EnvironmentParams", "default").Return("{}", nil)
env := &app.EnvironmentConfig{Path: "default"}
a.On("Environment", "default").Return(env, nil)
got, err := p.EnvParameters("/", false)
require.NoError(t, err)
require.Equal(t, "{ }\n", got)
......@@ -217,6 +243,56 @@ func Test_upgradeParams(t *testing.T) {
require.Equal(t, expected, got)
}
func Test_stubModule(t *testing.T) {
cases := []struct {
name string
module func() *cmocks.Module
expected string
isErr bool
}{
{
name: "valid",
module: func() *cmocks.Module {
module := &cmocks.Module{}
c := &cmocks.Component{}
c.On("Name", true).Return("app")
module.On("Components").Return([]component.Component{c}, nil)
return module
},
expected: `{"components":{"app":{}}}`,
},
{
name: "invalid components",
module: func() *cmocks.Module {
module := &cmocks.Module{}
module.On("Components").Return(nil, errors.New("failed"))
return module
},
isErr: true,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
require.NotNil(t, tc.module)
module := tc.module()
got, err := stubModule(module)
if tc.isErr {
require.Error(t, err)
return
}
require.NoError(t, err)
assert.Equal(t, tc.expected, got)
})
}
}
func withPipeline(t *testing.T, fn func(p *Pipeline, m *cmocks.Manager, a *appmocks.App)) {
a := &appmocks.App{}
a.On("Root").Return("/")
......
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