From 68fcbd21f83434997a51666f33582c2ada7caa7e Mon Sep 17 00:00:00 2001 From: bryanl <bryanliles@gmail.com> Date: Wed, 31 Jan 2018 22:12:29 -0500 Subject: [PATCH] Extract ksonnet generator extracts ksonnet generator to a new package to make it easier to incorporate in new code Signed-off-by: bryanl <bryanliles@gmail.com> --- generator/ksonnet.go | 62 ++++++++++++++++++++++++ generator/ksonnet_test.go | 92 ++++++++++++++++++++++++++++++++++++ metadata/clusterspec.go | 12 ++--- metadata/clusterspec_test.go | 4 +- metadata/environment.go | 49 ++++--------------- metadata/interface.go | 4 +- metadata/manager.go | 10 +++- 7 files changed, 180 insertions(+), 53 deletions(-) create mode 100644 generator/ksonnet.go create mode 100644 generator/ksonnet_test.go diff --git a/generator/ksonnet.go b/generator/ksonnet.go new file mode 100644 index 00000000..d19e3477 --- /dev/null +++ b/generator/ksonnet.go @@ -0,0 +1,62 @@ +package generator + +import ( + "encoding/json" + + "github.com/ksonnet/ksonnet-lib/ksonnet-gen/ksonnet" + "github.com/ksonnet/ksonnet-lib/ksonnet-gen/kubespec" + "github.com/ksonnet/ksonnet-lib/ksonnet-gen/kubeversion" + log "github.com/sirupsen/logrus" +) + +var ( + // ksonnetEmitter is the function which emits the ksonnet standard library. + ksonnetEmitter = ksonnet.Emit +) + +// KsonnetLib is the ksonnet standard library for a version of swagger. +type KsonnetLib struct { + // K is ksonnet extensions. + K []byte + // K is the generated ksonnet library. + K8s []byte + // Swagger is the swagger JSON used to generate the library. + Swagger []byte + // Version is the API version of the swagger. + Version string +} + +// Ksonnet generates the ksonnet standard library or returns an error if there was +// a problem. +func Ksonnet(swaggerData []byte) (*KsonnetLib, error) { + // Deserialize the API object. + s := kubespec.APISpec{} + if err := json.Unmarshal(swaggerData, &s); err != nil { + return nil, err + } + + s.Text = swaggerData + + // Emit Jsonnet code. + extensionsLibData, k8sLibData, err := ksonnetEmitter(&s, nil, nil) + if err != nil { + return nil, err + } + + // Warn where the Kubernetes version is currently only supported as Beta. + if kubeversion.Beta(s.Info.Version) { + log.Warnf(`! +============================================================================================ +Kubernetes version %s is currently supported as Beta; you may encounter unexpected behavior +============================================================================================`, s.Info.Version) + } + + kl := &KsonnetLib{ + K: extensionsLibData, + K8s: k8sLibData, + Swagger: swaggerData, + Version: s.Info.Version, + } + + return kl, nil +} diff --git a/generator/ksonnet_test.go b/generator/ksonnet_test.go new file mode 100644 index 00000000..165dc12d --- /dev/null +++ b/generator/ksonnet_test.go @@ -0,0 +1,92 @@ +package generator + +import ( + "errors" + "testing" + + "github.com/ksonnet/ksonnet-lib/ksonnet-gen/kubespec" +) + +func TestKsonnet(t *testing.T) { + ogEmitter := ksonnetEmitter + defer func() { + ksonnetEmitter = ogEmitter + }() + + var ( + ext = []byte("k") + lib = []byte("k8s") + successfulEmit = func(*kubespec.APISpec, *string, *string) ([]byte, []byte, error) { + return ext, lib, nil + } + failureEmit = func(*kubespec.APISpec, *string, *string) ([]byte, []byte, error) { + return nil, nil, errors.New("failure") + } + v170swagger = []byte(`{"info":{"version":"v1.7.0"}}`) + v180swagger = []byte(`{"info":{"version":"v1.8.0"}}`) + ) + + cases := []struct { + name string + emitter func(*kubespec.APISpec, *string, *string) ([]byte, []byte, error) + swaggerData []byte + version string + isErr bool + }{ + { + name: "valid swagger", + emitter: successfulEmit, + swaggerData: v170swagger, + version: "v1.7.0", + }, + { + name: "invalid swagger", + swaggerData: []byte(`{`), + isErr: true, + }, + { + name: "emitter error", + emitter: failureEmit, + swaggerData: v170swagger, + isErr: true, + }, + { + name: "valid beta swagger", + emitter: successfulEmit, + swaggerData: v180swagger, + version: "v1.8.0", + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + ksonnetEmitter = tc.emitter + + kl, err := Ksonnet(tc.swaggerData) + + if tc.isErr { + if err == nil { + t.Fatal("Ksonnet() should have returned an error") + } + } else { + if err != nil { + t.Fatal("Ksonnet() returned unexpected error") + } + + if got, expected := string(kl.K), string(ext); got != expected { + t.Errorf("Ksonnet() K = %s; expected = %s", got, expected) + } + if got, expected := string(kl.K8s), string(lib); got != expected { + t.Errorf("Ksonnet() K8s = %s; expected = %s", got, expected) + } + if got, expected := string(kl.Swagger), string(tc.swaggerData); got != expected { + t.Errorf("Ksonnet() Swagger = %s; expected = %s", got, expected) + } + if got, expected := string(kl.Version), tc.version; got != expected { + t.Errorf("Ksonnet() Version = %s; expected = %s", got, expected) + } + } + }) + } + +} diff --git a/metadata/clusterspec.go b/metadata/clusterspec.go index a3c3f02b..57412a7e 100644 --- a/metadata/clusterspec.go +++ b/metadata/clusterspec.go @@ -42,11 +42,11 @@ type clusterSpecFile struct { fs afero.Fs } -func (cs *clusterSpecFile) data() ([]byte, error) { +func (cs *clusterSpecFile) OpenAPI() ([]byte, error) { return afero.ReadFile(cs.fs, string(cs.specPath)) } -func (cs *clusterSpecFile) resource() string { +func (cs *clusterSpecFile) Resource() string { return string(cs.specPath) } @@ -54,11 +54,11 @@ type clusterSpecLive struct { apiServerURL string } -func (cs *clusterSpecLive) data() ([]byte, error) { +func (cs *clusterSpecLive) OpenAPI() ([]byte, error) { return nil, fmt.Errorf("Initializing from OpenAPI spec in live cluster is not implemented") } -func (cs *clusterSpecLive) resource() string { +func (cs *clusterSpecLive) Resource() string { return string(cs.apiServerURL) } @@ -66,7 +66,7 @@ type clusterSpecVersion struct { k8sVersion string } -func (cs *clusterSpecVersion) data() ([]byte, error) { +func (cs *clusterSpecVersion) OpenAPI() ([]byte, error) { versionURL := fmt.Sprintf(k8sVersionURLTemplate, cs.k8sVersion) resp, err := http.Get(versionURL) if err != nil { @@ -83,6 +83,6 @@ func (cs *clusterSpecVersion) data() ([]byte, error) { return ioutil.ReadAll(resp.Body) } -func (cs *clusterSpecVersion) resource() string { +func (cs *clusterSpecVersion) Resource() string { return string(cs.k8sVersion) } diff --git a/metadata/clusterspec_test.go b/metadata/clusterspec_test.go index 3a4f28f8..f300b128 100644 --- a/metadata/clusterspec_test.go +++ b/metadata/clusterspec_test.go @@ -23,8 +23,8 @@ func TestClusterSpecParsingSuccess(t *testing.T) { t.Errorf("Failed to parse spec: %v", err) } - parsedResource := parsed.resource() - targetResource := test.target.resource() + parsedResource := parsed.Resource() + targetResource := test.target.Resource() switch pt := parsed.(type) { case *clusterSpecLive: diff --git a/metadata/environment.go b/metadata/environment.go index 3c3cea73..042a90a1 100644 --- a/metadata/environment.go +++ b/metadata/environment.go @@ -27,9 +27,7 @@ import ( log "github.com/sirupsen/logrus" "github.com/spf13/afero" - "github.com/ksonnet/ksonnet-lib/ksonnet-gen/ksonnet" - "github.com/ksonnet/ksonnet-lib/ksonnet-gen/kubespec" - "github.com/ksonnet/ksonnet-lib/ksonnet-gen/kubeversion" + "github.com/ksonnet/ksonnet/generator" param "github.com/ksonnet/ksonnet/metadata/params" "github.com/ksonnet/ksonnet/utils" ) @@ -75,13 +73,18 @@ type EnvironmentSpec struct { } func (m *manager) CreateEnvironment(name, server, namespace string, spec ClusterSpec) error { - extensionsLibData, k8sLibData, specData, err := m.generateKsonnetLibData(spec) + b, err := spec.OpenAPI() + if err != nil { + return err + } + + kl, err := generator.Ksonnet(b) if err != nil { log.Debugf("Failed to write '%s'", specFilename) return err } - err = m.createEnvironment(name, server, namespace, extensionsLibData, k8sLibData, specData) + err = m.createEnvironment(name, server, namespace, kl.K, kl.K8s, kl.Swagger) if err == nil { log.Infof("Environment '%s' pointing to namespace '%s' and server address at '%s' successfully created", name, namespace, server) } @@ -497,42 +500,6 @@ func (m *manager) cleanEmptyParentDirs(name string) error { return nil } -func (m *manager) generateKsonnetLibData(spec ClusterSpec) ([]byte, []byte, []byte, error) { - // Get cluster specification data, possibly from the network. - text, err := spec.data() - if err != nil { - return nil, nil, nil, err - } - - ksonnetLibDir := appendToAbsPath(m.environmentsPath, defaultEnvName) - - // Deserialize the API object. - s := kubespec.APISpec{} - err = json.Unmarshal(text, &s) - if err != nil { - return nil, nil, nil, err - } - - s.Text = text - s.FilePath = filepath.Dir(string(ksonnetLibDir)) - - // Emit Jsonnet code. - extensionsLibData, k8sLibData, err := ksonnet.Emit(&s, nil, nil) - if err != nil { - return nil, nil, nil, err - } - - // Warn where the Kubernetes version is currently only supported as Beta. - if kubeversion.Beta(s.Info.Version) { - log.Warnf(`! -============================================================================================ -Kubernetes version %s is currently supported as Beta; you may encounter unexpected behavior -============================================================================================`, s.Info.Version) - } - - return extensionsLibData, k8sLibData, text, nil -} - func (m *manager) generateOverrideData() []byte { const ( relBaseLibsonnetPath = "../" + baseLibsonnetFile diff --git a/metadata/interface.go b/metadata/interface.go index f0ae8722..4dddf18d 100644 --- a/metadata/interface.go +++ b/metadata/interface.go @@ -119,8 +119,8 @@ func Init(name string, rootPath AbsPath, spec ClusterSpec, serverURI, namespace // OpenAPI spec in some file, or consulting the OpenAPI spec released in a // specific version of Kubernetes. type ClusterSpec interface { - data() ([]byte, error) - resource() string // For testing parsing logic. + OpenAPI() ([]byte, error) + Resource() string // For testing parsing logic. } // ParseClusterSpec will parse a cluster spec flag and output a well-formed diff --git a/metadata/manager.go b/metadata/manager.go index 0d4b337b..19128b3c 100644 --- a/metadata/manager.go +++ b/metadata/manager.go @@ -21,6 +21,7 @@ import ( "path" "path/filepath" + "github.com/ksonnet/ksonnet/generator" "github.com/ksonnet/ksonnet/metadata/app" param "github.com/ksonnet/ksonnet/metadata/params" "github.com/ksonnet/ksonnet/metadata/registry" @@ -117,7 +118,12 @@ func initManager(name string, rootPath AbsPath, spec ClusterSpec, serverURI, nam // either (e.g., GET'ing the spec from a live cluster returns 404) does not // result in a partially-initialized directory structure. // - extensionsLibData, k8sLibData, specData, err := m.generateKsonnetLibData(spec) + b, err := spec.OpenAPI() + if err != nil { + return nil, err + } + + kl, err := generator.Ksonnet(b) if err != nil { return nil, err } @@ -149,7 +155,7 @@ func initManager(name string, rootPath AbsPath, spec ClusterSpec, serverURI, nam // Initialize environment, and cache specification data. if serverURI != nil { - err := m.createEnvironment(defaultEnvName, *serverURI, *namespace, extensionsLibData, k8sLibData, specData) + err := m.createEnvironment(defaultEnvName, *serverURI, *namespace, kl.K, kl.K8s, kl.Swagger) if err != nil { return nil, errorOnCreateFailure(name, err) } -- GitLab