Skip to content
Snippets Groups Projects
Unverified Commit 66acf7bd authored by Bryan Liles's avatar Bryan Liles Committed by GitHub
Browse files

Merge pull request #301 from bryanl/use-afero-when-possible

use afero when possible
parents 44affd77 245c7bd3
No related branches found
No related tags found
No related merge requests found
......@@ -116,7 +116,13 @@ var applyCmd = &cobra.Command{
return err
}
objs, err := expandEnvCmdObjs(cmd, env, componentNames, wd)
te := newCmdObjExpander(cmdObjExpanderConfig{
cmd: cmd,
env: env,
components: componentNames,
cwd: wd,
})
objs, err := te.Expand()
if err != nil {
return err
}
......
......@@ -78,7 +78,13 @@ var deleteCmd = &cobra.Command{
return err
}
objs, err := expandEnvCmdObjs(cmd, env, componentNames, wd)
te := newCmdObjExpander(cmdObjExpanderConfig{
cmd: cmd,
env: env,
components: componentNames,
cwd: wd,
})
objs, err := te.Expand()
if err != nil {
return err
}
......
......@@ -23,6 +23,7 @@ import (
"k8s.io/client-go/discovery"
"k8s.io/client-go/dynamic"
"github.com/spf13/afero"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/client-go/tools/clientcmd"
......@@ -82,7 +83,7 @@ var diffCmd = &cobra.Command{
return err
}
c, err := initDiffCmd(cmd, wd, env1, env2, componentNames, diffStrategy)
c, err := initDiffCmd(appFs, cmd, wd, env1, env2, componentNames, diffStrategy)
if err != nil {
return err
}
......@@ -140,14 +141,14 @@ ks diff dev -c redis
`,
}
func initDiffCmd(cmd *cobra.Command, wd metadata.AbsPath, envFq1, envFq2 *string, files []string, diffStrategy string) (kubecfg.DiffCmd, error) {
func initDiffCmd(fs afero.Fs, cmd *cobra.Command, wd metadata.AbsPath, envFq1, envFq2 *string, files []string, diffStrategy string) (kubecfg.DiffCmd, error) {
const (
remote = "remote"
local = "local"
)
if envFq2 == nil {
return initDiffSingleEnv(*envFq1, diffStrategy, files, cmd, wd)
return initDiffSingleEnv(fs, *envFq1, diffStrategy, files, cmd, wd)
}
// expect envs to be of the format local:myenv or remote:myenv
......@@ -168,11 +169,11 @@ func initDiffCmd(cmd *cobra.Command, wd metadata.AbsPath, envFq1, envFq2 *string
}
if env1[0] == local && env2[0] == local {
return initDiffLocalCmd(env1[1], env2[1], diffStrategy, cmd, manager)
return initDiffLocalCmd(fs, env1[1], env2[1], diffStrategy, cmd, manager)
}
if env1[0] == remote && env2[0] == remote {
return initDiffRemotesCmd(env1[1], env2[1], diffStrategy, cmd, manager)
return initDiffRemotesCmd(fs, env1[1], env2[1], diffStrategy, cmd, manager)
}
localEnv := env1[1]
......@@ -181,11 +182,11 @@ func initDiffCmd(cmd *cobra.Command, wd metadata.AbsPath, envFq1, envFq2 *string
localEnv = env2[1]
remoteEnv = env1[1]
}
return initDiffRemoteCmd(localEnv, remoteEnv, diffStrategy, cmd, manager)
return initDiffRemoteCmd(fs, localEnv, remoteEnv, diffStrategy, cmd, manager)
}
// initDiffSingleEnv sets up configurations for diffing using one environment
func initDiffSingleEnv(env, diffStrategy string, files []string, cmd *cobra.Command, wd metadata.AbsPath) (kubecfg.DiffCmd, error) {
func initDiffSingleEnv(fs afero.Fs, env, diffStrategy string, files []string, cmd *cobra.Command, wd metadata.AbsPath) (kubecfg.DiffCmd, error) {
c := kubecfg.DiffRemoteCmd{}
c.DiffStrategy = diffStrategy
c.Client = &kubecfg.Client{}
......@@ -195,7 +196,13 @@ func initDiffSingleEnv(env, diffStrategy string, files []string, cmd *cobra.Comm
return nil, fmt.Errorf("single <env> argument with prefix 'local:' or 'remote:' not allowed")
}
c.Client.APIObjects, err = expandEnvCmdObjs(cmd, env, files, wd)
te := newCmdObjExpander(cmdObjExpanderConfig{
cmd: cmd,
env: env,
components: files,
cwd: wd,
})
c.Client.APIObjects, err = te.Expand()
if err != nil {
return nil, err
}
......@@ -214,21 +221,21 @@ func initDiffSingleEnv(env, diffStrategy string, files []string, cmd *cobra.Comm
}
// initDiffLocalCmd sets up configurations for diffing between two sets of expanded Kubernetes objects locally
func initDiffLocalCmd(env1, env2, diffStrategy string, cmd *cobra.Command, m metadata.Manager) (kubecfg.DiffCmd, error) {
func initDiffLocalCmd(fs afero.Fs, env1, env2, diffStrategy string, cmd *cobra.Command, m metadata.Manager) (kubecfg.DiffCmd, error) {
c := kubecfg.DiffLocalCmd{}
c.DiffStrategy = diffStrategy
var err error
c.Env1 = &kubecfg.LocalEnv{}
c.Env1.Name = env1
c.Env1.APIObjects, err = expandEnvObjs(cmd, c.Env1.Name, m)
c.Env1.APIObjects, err = expandEnvObjs(fs, cmd, c.Env1.Name, m)
if err != nil {
return nil, err
}
c.Env2 = &kubecfg.LocalEnv{}
c.Env2.Name = env2
c.Env2.APIObjects, err = expandEnvObjs(cmd, c.Env2.Name, m)
c.Env2.APIObjects, err = expandEnvObjs(fs, cmd, c.Env2.Name, m)
if err != nil {
return nil, err
}
......@@ -237,7 +244,7 @@ func initDiffLocalCmd(env1, env2, diffStrategy string, cmd *cobra.Command, m met
}
// initDiffRemotesCmd sets up configurations for diffing between objects on two remote clusters
func initDiffRemotesCmd(env1, env2, diffStrategy string, cmd *cobra.Command, m metadata.Manager) (kubecfg.DiffCmd, error) {
func initDiffRemotesCmd(fs afero.Fs, env1, env2, diffStrategy string, cmd *cobra.Command, m metadata.Manager) (kubecfg.DiffCmd, error) {
c := kubecfg.DiffRemotesCmd{}
c.DiffStrategy = diffStrategy
......@@ -248,11 +255,11 @@ func initDiffRemotesCmd(env1, env2, diffStrategy string, cmd *cobra.Command, m m
c.ClientB.Name = env2
var err error
c.ClientA.APIObjects, err = expandEnvObjs(cmd, c.ClientA.Name, m)
c.ClientA.APIObjects, err = expandEnvObjs(fs, cmd, c.ClientA.Name, m)
if err != nil {
return nil, err
}
c.ClientB.APIObjects, err = expandEnvObjs(cmd, c.ClientB.Name, m)
c.ClientB.APIObjects, err = expandEnvObjs(fs, cmd, c.ClientB.Name, m)
if err != nil {
return nil, err
}
......@@ -270,13 +277,13 @@ func initDiffRemotesCmd(env1, env2, diffStrategy string, cmd *cobra.Command, m m
}
// initDiffRemoteCmd sets up configurations for diffing between local objects and objects on a remote cluster
func initDiffRemoteCmd(localEnv, remoteEnv, diffStrategy string, cmd *cobra.Command, m metadata.Manager) (kubecfg.DiffCmd, error) {
func initDiffRemoteCmd(fs afero.Fs, localEnv, remoteEnv, diffStrategy string, cmd *cobra.Command, m metadata.Manager) (kubecfg.DiffCmd, error) {
c := kubecfg.DiffRemoteCmd{}
c.DiffStrategy = diffStrategy
c.Client = &kubecfg.Client{}
var err error
c.Client.APIObjects, err = expandEnvObjs(cmd, localEnv, m)
c.Client.APIObjects, err = expandEnvObjs(fs, cmd, localEnv, m)
if err != nil {
return nil, err
}
......@@ -309,8 +316,8 @@ func setupClientConfig(env *string, cmd *cobra.Command) (dynamic.ClientPool, dis
}
// expandEnvObjs finds and expands templates for an environment
func expandEnvObjs(cmd *cobra.Command, env string, manager metadata.Manager) ([]*unstructured.Unstructured, error) {
expander, err := newExpander(cmd)
func expandEnvObjs(fs afero.Fs, cmd *cobra.Command, env string, manager metadata.Manager) ([]*unstructured.Unstructured, error) {
expander, err := newExpander(fs, cmd)
if err != nil {
return nil, err
}
......
......@@ -29,7 +29,9 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"github.com/spf13/afero"
"github.com/spf13/cobra"
"golang.org/x/crypto/ssh/terminal"
"k8s.io/client-go/discovery"
......@@ -61,11 +63,16 @@ const (
flagComponentShort = "c"
)
var clientConfig clientcmd.ClientConfig
var overrides clientcmd.ConfigOverrides
var loadingRules clientcmd.ClientConfigLoadingRules
var (
clientConfig clientcmd.ClientConfig
overrides clientcmd.ConfigOverrides
loadingRules clientcmd.ClientConfigLoadingRules
appFs afero.Fs
)
func init() {
appFs = afero.NewOsFs()
RootCmd.PersistentFlags().CountP(flagVerbose, "v", "Increase verbosity. May be given multiple times.")
// The "usual" clientcmd/kubectl flags
......@@ -222,9 +229,9 @@ func (f *logFormatter) Format(e *log.Entry) ([]byte, error) {
return buf.Bytes(), nil
}
func newExpander(cmd *cobra.Command) (*template.Expander, error) {
func newExpander(fs afero.Fs, cmd *cobra.Command) (*template.Expander, error) {
flags := cmd.Flags()
spec := template.Expander{}
spec := template.NewExpander(fs)
var err error
spec.EnvJPath = filepath.SplitList(os.Getenv("KUBECFG_JPATH"))
......@@ -379,39 +386,64 @@ func overrideCluster(envName string, clientConfig clientcmd.ClientConfig, overri
return fmt.Errorf("Attempting to deploy to environment '%s' at '%s', but cannot locate a server at that address", envName, env.Server)
}
// expandEnvCmdObjs finds and expands templates for the family of commands of
type cmdObjExpanderConfig struct {
fs afero.Fs
cmd *cobra.Command
env string
components []string
cwd metadata.AbsPath
}
// cmdObjExpander finds and expands templates for the family of commands of
// the form `[<env>|-f <file-name>]`, e.g., `apply` and `delete`. That is, if
// the user passes a list of files, we will expand all templates in those files,
// while if a user passes an environment name, we will expand all component
// files using that environment.
func expandEnvCmdObjs(cmd *cobra.Command, env string, components []string, cwd metadata.AbsPath) ([]*unstructured.Unstructured, error) {
expander, err := newExpander(cmd)
type cmdObjExpander struct {
config cmdObjExpanderConfig
templateExpanderFn func(afero.Fs, *cobra.Command) (*template.Expander, error)
}
func newCmdObjExpander(c cmdObjExpanderConfig) *cmdObjExpander {
if c.fs == nil {
c.fs = appFs
}
return &cmdObjExpander{
config: c,
templateExpanderFn: newExpander,
}
}
// Expands expands the templates.
func (te *cmdObjExpander) Expand() ([]*unstructured.Unstructured, error) {
expander, err := te.templateExpanderFn(te.config.fs, te.config.cmd)
if err != nil {
return nil, err
return nil, errors.Wrap(err, "template expander")
}
//
// Set up the template expander to be able to expand the ksonnet application.
//
manager, err := metadata.Find(cwd)
manager, err := metadata.Find(te.config.cwd)
if err != nil {
return nil, err
return nil, errors.Wrap(err, "find metadata")
}
libPath, vendorPath := manager.LibPaths()
metadataPath, mainPath, paramsPath, specPath := manager.EnvPaths(env)
metadataPath, mainPath, paramsPath, specPath := manager.EnvPaths(te.config.env)
expander.FlagJpath = append([]string{string(libPath), string(vendorPath), string(metadataPath)}, expander.FlagJpath...)
componentPaths, err := manager.ComponentPaths()
if err != nil {
return nil, err
return nil, errors.Wrap(err, "component paths")
}
baseObj, err := constructBaseObj(componentPaths, components)
baseObj, err := constructBaseObj(componentPaths, te.config.components)
if err != nil {
return nil, err
return nil, errors.Wrap(err, "construct base object")
}
//
......
......@@ -99,7 +99,13 @@ ks show dev -c redis -c nginx-server
}
wd := metadata.AbsPath(cwd)
objs, err := expandEnvCmdObjs(cmd, env, componentNames, wd)
te := newCmdObjExpander(cmdObjExpanderConfig{
cmd: cmd,
env: env,
components: componentNames,
cwd: wd,
})
objs, err := te.Expand()
if err != nil {
return err
}
......
......@@ -66,7 +66,13 @@ var validateCmd = &cobra.Command{
return err
}
objs, err := expandEnvCmdObjs(cmd, env, componentNames, wd)
te := newCmdObjExpander(cmdObjExpanderConfig{
cmd: cmd,
env: env,
components: componentNames,
cwd: wd,
})
objs, err := te.Expand()
if err != nil {
return err
}
......
......@@ -2,7 +2,6 @@ package template
import (
"fmt"
"io/ioutil"
"os"
"strings"
......@@ -11,6 +10,7 @@ import (
jsonnet "github.com/google/go-jsonnet"
"github.com/ksonnet/ksonnet/utils"
log "github.com/sirupsen/logrus"
"github.com/spf13/afero"
)
type Expander struct {
......@@ -24,8 +24,21 @@ type Expander struct {
Resolver string
FailAction string
fs afero.Fs
}
func NewExpander(fs afero.Fs) Expander {
if fs == nil {
fs = afero.NewOsFs()
}
return Expander{
fs: fs,
}
}
// Expand expands paths to a slice of v1 Unstructured objects.
func (spec *Expander) Expand(paths []string) ([]*unstructured.Unstructured, error) {
vm, err := spec.jsonnetVM()
if err != nil {
......@@ -34,7 +47,7 @@ func (spec *Expander) Expand(paths []string) ([]*unstructured.Unstructured, erro
res := []*unstructured.Unstructured{}
for _, path := range paths {
objs, err := utils.Read(vm, path)
objs, err := utils.Read(spec.fs, vm, path)
if err != nil {
return nil, fmt.Errorf("Error reading %s: %v", path, err)
}
......@@ -83,7 +96,7 @@ func (spec *Expander) jsonnetVM() (*jsonnet.VM, error) {
if len(kv) != 2 {
return nil, fmt.Errorf("Failed to parse ext var files: missing '=' in %s", extvar)
}
v, err := ioutil.ReadFile(kv[1])
v, err := afero.ReadFile(spec.fs, kv[1])
if err != nil {
return nil, err
}
......@@ -110,7 +123,7 @@ func (spec *Expander) jsonnetVM() (*jsonnet.VM, error) {
if len(kv) != 2 {
return nil, fmt.Errorf("Failed to parse tla var files: missing '=' in %s", tlavar)
}
v, err := ioutil.ReadFile(kv[1])
v, err := afero.ReadFile(spec.fs, kv[1])
if err != nil {
return nil, err
}
......
......@@ -26,6 +26,7 @@ import (
jsonnet "github.com/google/go-jsonnet"
log "github.com/sirupsen/logrus"
"github.com/spf13/afero"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/yaml"
......@@ -34,7 +35,7 @@ import (
// Read fetches and decodes K8s objects by path.
// TODO: Replace this with something supporting more sophisticated
// content negotiation.
func Read(vm *jsonnet.VM, path string) ([]runtime.Object, error) {
func Read(fs afero.Fs, vm *jsonnet.VM, path string) ([]runtime.Object, error) {
ext := filepath.Ext(path)
if ext == ".json" {
f, err := os.Open(path)
......@@ -51,7 +52,7 @@ func Read(vm *jsonnet.VM, path string) ([]runtime.Object, error) {
defer f.Close()
return yamlReader(f)
} else if ext == ".jsonnet" {
return jsonnetReader(vm, path)
return jsonnetReader(fs, vm, path)
}
return nil, fmt.Errorf("Unknown file extension: %s", path)
......@@ -125,8 +126,8 @@ func jsonWalk(obj interface{}) ([]interface{}, error) {
}
}
func jsonnetReader(vm *jsonnet.VM, path string) ([]runtime.Object, error) {
jsonnetBytes, err := ioutil.ReadFile(path)
func jsonnetReader(fs afero.Fs, vm *jsonnet.VM, path string) ([]runtime.Object, error) {
jsonnetBytes, err := afero.ReadFile(fs, path)
if err != nil {
return nil, err
}
......
......@@ -18,13 +18,13 @@ package utils
import (
"encoding/json"
"fmt"
"io/ioutil"
"path"
"path/filepath"
"strings"
"testing"
swagger "github.com/emicklei/go-restful-swagger12"
"github.com/spf13/afero"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
......@@ -32,11 +32,12 @@ import (
type schemaFromFile struct {
dir string
fs afero.Fs
}
func (s schemaFromFile) SwaggerSchema(gv schema.GroupVersion) (*swagger.ApiDeclaration, error) {
file := path.Join(s.dir, fmt.Sprintf("schema-%s.json", gv))
data, err := ioutil.ReadFile(file)
data, err := afero.ReadFile(s.fs, file)
if err != nil {
return nil, err
}
......@@ -50,7 +51,7 @@ func (s schemaFromFile) SwaggerSchema(gv schema.GroupVersion) (*swagger.ApiDecla
}
func TestValidate(t *testing.T) {
schemaReader := schemaFromFile{dir: filepath.FromSlash("../testdata")}
schemaReader := schemaFromFile{dir: filepath.FromSlash("../testdata"), fs: afero.NewOsFs()}
s, err := NewSwaggerSchemaFor(schemaReader, schema.GroupVersion{Version: "v1"})
if err != nil {
t.Fatalf("Error reading schema: %v", err)
......
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