diff --git a/metadata/clusterspec.go b/metadata/clusterspec.go
index bbe44dd15bdc584da78dcd062f2cc11441ee948e..a3c3f02b56c595cc19d5b17aedc400072986f1f0 100644
--- a/metadata/clusterspec.go
+++ b/metadata/clusterspec.go
@@ -1,15 +1,49 @@
 package metadata
 
 import (
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"path/filepath"
+	"strings"
+
 	"github.com/spf13/afero"
 )
 
+const (
+	k8sVersionURLTemplate = "https://raw.githubusercontent.com/kubernetes/kubernetes/%s/api/openapi-spec/swagger.json"
+)
+
+func parseClusterSpec(specFlag string, fs afero.Fs) (ClusterSpec, error) {
+	split := strings.SplitN(specFlag, ":", 2)
+	if len(split) <= 1 || split[1] == "" {
+		return nil, fmt.Errorf("Invalid API specification '%s'", specFlag)
+	}
+
+	switch split[0] {
+	case "version":
+		return &clusterSpecVersion{k8sVersion: split[1]}, nil
+	case "file":
+		abs, err := filepath.Abs(split[1])
+		if err != nil {
+			return nil, err
+		}
+		absPath := AbsPath(abs)
+		return &clusterSpecFile{specPath: absPath, fs: fs}, nil
+	case "url":
+		return &clusterSpecLive{apiServerURL: split[1]}, nil
+	default:
+		return nil, fmt.Errorf("Could not parse cluster spec '%s'", specFlag)
+	}
+}
+
 type clusterSpecFile struct {
 	specPath AbsPath
+	fs       afero.Fs
 }
 
 func (cs *clusterSpecFile) data() ([]byte, error) {
-	return afero.ReadFile(appFS, string(cs.specPath))
+	return afero.ReadFile(cs.fs, string(cs.specPath))
 }
 
 func (cs *clusterSpecFile) resource() string {
@@ -21,8 +55,7 @@ type clusterSpecLive struct {
 }
 
 func (cs *clusterSpecLive) data() ([]byte, error) {
-	// TODO: Implement getting spec from path, k8sVersion, and URL.
-	panic("Not implemented")
+	return nil, fmt.Errorf("Initializing from OpenAPI spec in live cluster is not implemented")
 }
 
 func (cs *clusterSpecLive) resource() string {
@@ -34,8 +67,20 @@ type clusterSpecVersion struct {
 }
 
 func (cs *clusterSpecVersion) data() ([]byte, error) {
-	// TODO: Implement getting spec from path, k8sVersion, and URL.
-	panic("Not implemented")
+	versionURL := fmt.Sprintf(k8sVersionURLTemplate, cs.k8sVersion)
+	resp, err := http.Get(versionURL)
+	if err != nil {
+		return nil, err
+	}
+	defer resp.Body.Close()
+
+	if resp.StatusCode != 200 {
+		return nil, fmt.Errorf(
+			"Recieved status code '%d' when trying to retrieve OpenAPI schema for cluster version '%s' from URL '%s'",
+			resp.StatusCode, cs.k8sVersion, versionURL)
+	}
+
+	return ioutil.ReadAll(resp.Body)
 }
 
 func (cs *clusterSpecVersion) resource() string {
diff --git a/metadata/clusterspec_test.go b/metadata/clusterspec_test.go
index 4d13beda69ff703293c4cf29e4546c30a51aeccf..3a4f28f896a8e4e04d196ede6efe1bf14c65fad9 100644
--- a/metadata/clusterspec_test.go
+++ b/metadata/clusterspec_test.go
@@ -12,13 +12,13 @@ type parseSuccess struct {
 
 var successTests = []parseSuccess{
 	{"version:v1.7.1", &clusterSpecVersion{"v1.7.1"}},
-	{"file:swagger.json", &clusterSpecFile{"swagger.json"}},
+	{"file:swagger.json", &clusterSpecFile{"swagger.json", testFS}},
 	{"url:file:///some_file", &clusterSpecLive{"file:///some_file"}},
 }
 
 func TestClusterSpecParsingSuccess(t *testing.T) {
 	for _, test := range successTests {
-		parsed, err := ParseClusterSpec(test.input)
+		parsed, err := parseClusterSpec(test.input, testFS)
 		if err != nil {
 			t.Errorf("Failed to parse spec: %v", err)
 		}
@@ -66,7 +66,7 @@ var failureTests = []parseFailure{
 
 func TestClusterSpecParsingFailure(t *testing.T) {
 	for _, test := range failureTests {
-		_, err := ParseClusterSpec(test.input)
+		_, err := parseClusterSpec(test.input, testFS)
 		if err == nil {
 			t.Errorf("Cluster spec parse for '%s' should have failed, but succeeded", test.input)
 		} else if msg := err.Error(); msg != test.errorMsg {
diff --git a/metadata/interface.go b/metadata/interface.go
index 5d9ed9e39458da38ff544adde7b4e9c890df77ba..bfa05ea8fc856f788d3d05f6ee1dea8965311e94 100644
--- a/metadata/interface.go
+++ b/metadata/interface.go
@@ -1,13 +1,11 @@
 package metadata
 
 import (
-	"fmt"
-	"path/filepath"
-	"strings"
-
 	"github.com/spf13/afero"
 )
 
+var appFS afero.Fs
+
 // AbsPath is an advisory type that represents an absolute path. It is advisory
 // in that it is not forced to be absolute, but rather, meant to indicate
 // intent, and make code easier to read.
@@ -40,7 +38,7 @@ func Find(path AbsPath) (Manager, error) {
 // capabilities-compliant version of ksonnet-lib, and then generate the
 // directory tree for an application.
 func Init(rootPath AbsPath, spec ClusterSpec) (Manager, error) {
-	return initManager(rootPath, spec, afero.NewOsFs())
+	return initManager(rootPath, spec, appFS)
 }
 
 // ClusterSpec represents the API supported by some cluster. There are several
@@ -57,24 +55,9 @@ type ClusterSpec interface {
 // will output a ClusterSpec representing the cluster specification associated
 // with the `v1.7.1` build of Kubernetes.
 func ParseClusterSpec(specFlag string) (ClusterSpec, error) {
-	split := strings.SplitN(specFlag, ":", 2)
-	if len(split) == 0 || len(split) == 1 || split[1] == "" {
-		return nil, fmt.Errorf("Invalid API specification '%s'", specFlag)
-	}
+	return parseClusterSpec(specFlag, appFS)
+}
 
-	switch split[0] {
-	case "version":
-		return &clusterSpecVersion{k8sVersion: split[1]}, nil
-	case "file":
-		abs, err := filepath.Abs(split[1])
-		if err != nil {
-			return nil, err
-		}
-		absPath := AbsPath(abs)
-		return &clusterSpecFile{specPath: absPath}, nil
-	case "url":
-		return &clusterSpecLive{apiServerURL: split[1]}, nil
-	default:
-		return nil, fmt.Errorf("Could not parse cluster spec '%s'", specFlag)
-	}
+func init() {
+	appFS = afero.NewOsFs()
 }
diff --git a/metadata/manager_test.go b/metadata/manager_test.go
index d73fd97cc8c4f1e8bb332a3d35c9d40e680b70ee..5dabda9ff14d45333d6c4cad62039c7dd560061a 100644
--- a/metadata/manager_test.go
+++ b/metadata/manager_test.go
@@ -31,20 +31,20 @@ const (
 `
 )
 
-var appFS = afero.NewMemMapFs()
+var testFS = afero.NewMemMapFs()
 
 func init() {
-	afero.WriteFile(appFS, blankSwagger, []byte(blankSwaggerData), os.ModePerm)
+	afero.WriteFile(testFS, blankSwagger, []byte(blankSwaggerData), os.ModePerm)
 }
 
 func TestInitSuccess(t *testing.T) {
-	spec, err := ParseClusterSpec(fmt.Sprintf("file:%s", blankSwagger))
+	spec, err := parseClusterSpec(fmt.Sprintf("file:%s", blankSwagger), testFS)
 	if err != nil {
 		t.Fatalf("Failed to parse cluster spec: %v", err)
 	}
 
 	appPath := AbsPath("/fromEmptySwagger")
-	_, err = initManager(appPath, spec, appFS)
+	_, err = initManager(appPath, spec, testFS)
 	if err != nil {
 		t.Fatalf("Failed to init cluster spec: %v", err)
 	}
@@ -62,7 +62,7 @@ func TestInitSuccess(t *testing.T) {
 
 	for _, p := range paths {
 		path := appendToAbsPath(appPath, string(p))
-		exists, err := afero.DirExists(appFS, string(path))
+		exists, err := afero.DirExists(testFS, string(path))
 		if err != nil {
 			t.Fatalf("Expected to create directory '%s', but failed:\n%v", p, err)
 		} else if !exists {
@@ -72,7 +72,7 @@ func TestInitSuccess(t *testing.T) {
 
 	envPath := appendToAbsPath(appPath, string(defaultEnvDir))
 	schemaPath := appendToAbsPath(envPath, schemaFilename)
-	bytes, err := afero.ReadFile(appFS, string(schemaPath))
+	bytes, err := afero.ReadFile(testFS, string(schemaPath))
 	if err != nil {
 		t.Fatalf("Failed to read swagger file at '%s':\n%v", schemaPath, err)
 	} else if actualSwagger := string(bytes); actualSwagger != blankSwaggerData {
@@ -80,7 +80,7 @@ func TestInitSuccess(t *testing.T) {
 	}
 
 	ksonnetLibPath := appendToAbsPath(envPath, ksonnetLibCoreFilename)
-	ksonnetLibBytes, err := afero.ReadFile(appFS, string(ksonnetLibPath))
+	ksonnetLibBytes, err := afero.ReadFile(testFS, string(ksonnetLibPath))
 	if err != nil {
 		t.Fatalf("Failed to read ksonnet-lib file at '%s':\n%v", ksonnetLibPath, err)
 	} else if actualKsonnetLib := string(ksonnetLibBytes); actualKsonnetLib != blankKsonnetLib {
@@ -90,7 +90,7 @@ func TestInitSuccess(t *testing.T) {
 
 func TestFindSuccess(t *testing.T) {
 	findSuccess := func(t *testing.T, appDir, currDir AbsPath) {
-		m, err := findManager(currDir, appFS)
+		m, err := findManager(currDir, testFS)
 		if err != nil {
 			t.Fatalf("Failed to find manager at path '%s':\n%v", currDir, err)
 		} else if m.rootPath != appDir {
@@ -98,13 +98,13 @@ func TestFindSuccess(t *testing.T) {
 		}
 	}
 
-	spec, err := ParseClusterSpec(fmt.Sprintf("file:%s", blankSwagger))
+	spec, err := parseClusterSpec(fmt.Sprintf("file:%s", blankSwagger), testFS)
 	if err != nil {
 		t.Fatalf("Failed to parse cluster spec: %v", err)
 	}
 
 	appPath := AbsPath("/findSuccess")
-	_, err = initManager(appPath, spec, appFS)
+	_, err = initManager(appPath, spec, testFS)
 	if err != nil {
 		t.Fatalf("Failed to init cluster spec: %v", err)
 	}
@@ -116,7 +116,7 @@ func TestFindSuccess(t *testing.T) {
 
 	// Create empty app file.
 	appFile := appendToAbsPath(components, "app.jsonnet")
-	f, err := appFS.OpenFile(string(appFile), os.O_RDONLY|os.O_CREATE, 0777)
+	f, err := testFS.OpenFile(string(appFile), os.O_RDONLY|os.O_CREATE, 0777)
 	if err != nil {
 		t.Fatalf("Failed to touch app file '%s'\n%v", appFile, err)
 	}
@@ -127,7 +127,7 @@ func TestFindSuccess(t *testing.T) {
 
 func TestFindFailure(t *testing.T) {
 	findFailure := func(t *testing.T, currDir AbsPath) {
-		_, err := findManager(currDir, appFS)
+		_, err := findManager(currDir, testFS)
 		if err == nil {
 			t.Fatalf("Expected to fail to find ksonnet app in '%s', but succeeded", currDir)
 		}
@@ -139,20 +139,20 @@ func TestFindFailure(t *testing.T) {
 }
 
 func TestDoubleNewFailure(t *testing.T) {
-	spec, err := ParseClusterSpec(fmt.Sprintf("file:%s", blankSwagger))
+	spec, err := parseClusterSpec(fmt.Sprintf("file:%s", blankSwagger), testFS)
 	if err != nil {
 		t.Fatalf("Failed to parse cluster spec: %v", err)
 	}
 
 	appPath := AbsPath("/doubleNew")
 
-	_, err = initManager(appPath, spec, appFS)
+	_, err = initManager(appPath, spec, testFS)
 	if err != nil {
 		t.Fatalf("Failed to init cluster spec: %v", err)
 	}
 
 	targetErr := fmt.Sprintf("Could not create app; directory '%s' already exists", appPath)
-	_, err = initManager(appPath, spec, appFS)
+	_, err = initManager(appPath, spec, testFS)
 	if err == nil || err.Error() != targetErr {
 		t.Fatalf("Expected to fail to create app with message '%s', got '%s'", targetErr, err.Error())
 	}