diff --git a/generator/ksonnet.go b/generator/ksonnet.go
new file mode 100644
index 0000000000000000000000000000000000000000..d19e347738911b027f0f7533ad0936360006fc5a
--- /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 0000000000000000000000000000000000000000..165dc12dc1e3792f7053bfb82c0c05be879ac1a3
--- /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 a3c3f02b56c595cc19d5b17aedc400072986f1f0..57412a7eb6c1fa246feebf28438044c2887a7635 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 3a4f28f896a8e4e04d196ede6efe1bf14c65fad9..f300b128cefdc32dd3362a17361c5894bab4a8fc 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 3c3cea73174f8f5d3e86d1b167cfbafb8258a505..042a90a1fef219c5275377ecad354ab18306bf7c 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 f0ae872226113bdd400f7b9d7945fb3a4713b14e..4dddf18d82865be94d93286aaf722495e47b787a 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 0d4b337b991eda18815ae726fe0ab871cbc7500e..19128b3cadfbbeba9427045aa4967865dc315fb0 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)
 		}