From 98c7428f1221bf36bd83fb9d6a48dce1d8c7f695 Mon Sep 17 00:00:00 2001 From: Alex Clemmer <clemmer.alexander@gmail.com> Date: Sat, 9 Sep 2017 22:31:19 -0700 Subject: [PATCH] Emit `k.libsonnet` during `init` subcommand This commit fixes #113, causing us to emit `k.libsonnet` (a collection of extensions to the k8s API) by updating the dependency on `ksonnet-lib/ksonnet-gen` and exercising the new signature for `ksonnet.Emit`, which handles this automatically. We update the `vendor/` directory and the code that depends on it in the same commit so that we don't break bisect. --- metadata/manager.go | 27 +++--- metadata/manager_test.go | 20 +++-- .../ksonnet-lib/ksonnet-gen/ksonnet/emit.go | 11 ++- .../ksonnet-gen/kubeversion/data.go | 84 +++++++++++++++++++ .../ksonnet-gen/kubeversion/version.go | 12 +++ vendor/vendor.json | 20 ++--- 6 files changed, 146 insertions(+), 28 deletions(-) diff --git a/metadata/manager.go b/metadata/manager.go index b0809b4d..a89624e9 100644 --- a/metadata/manager.go +++ b/metadata/manager.go @@ -27,9 +27,10 @@ const ( defaultEnvName = "default" // Environment-specific files - schemaFilename = "swagger.json" - ksonnetLibCoreFilename = "k8s.libsonnet" - specFilename = "spec.json" + schemaFilename = "swagger.json" + extensionsLibFilename = "k.libsonnet" + k8sLibFilename = "k8s.libsonnet" + specFilename = "spec.json" ) type manager struct { @@ -82,7 +83,7 @@ func initManager(rootPath AbsPath, spec ClusterSpec, appFS afero.Fs) (*manager, // result in a partially-initialized directory structure. // ksonnetLibDir := appendToAbsPath(m.environmentsDir, defaultEnvName) - ksonnetLibData, err := generateKsonnetLibData(ksonnetLibDir, specData) + extensionsLibData, k8sLibData, err := generateKsonnetLibData(ksonnetLibDir, specData) if err != nil { return nil, err } @@ -93,7 +94,7 @@ func initManager(rootPath AbsPath, spec ClusterSpec, appFS afero.Fs) (*manager, } // Cache specification data. - if err = m.createEnvironment(defaultEnvName, specData, ksonnetLibData); err != nil { + if err = m.createEnvironment(defaultEnvName, specData, extensionsLibData, k8sLibData); err != nil { return nil, err } @@ -140,7 +141,7 @@ func (m *manager) LibPaths(envName string) (libPath, envLibPath AbsPath) { return m.libPath, appendToAbsPath(m.environmentsDir, envName) } -func (m *manager) createEnvironment(name string, specData, ksonnetLibData []byte) error { +func (m *manager) createEnvironment(name string, specData, extensionsLibData, k8sLibData []byte) error { envPath := appendToAbsPath(m.environmentsDir, name) err := m.appFS.MkdirAll(string(envPath), os.ModePerm) if err != nil { @@ -154,8 +155,14 @@ func (m *manager) createEnvironment(name string, specData, ksonnetLibData []byte return err } - ksonnetLibPath := appendToAbsPath(envPath, ksonnetLibCoreFilename) - err = afero.WriteFile(m.appFS, string(ksonnetLibPath), ksonnetLibData, 0644) + k8sLibPath := appendToAbsPath(envPath, k8sLibFilename) + err = afero.WriteFile(m.appFS, string(k8sLibPath), k8sLibData, 0644) + if err != nil { + return err + } + + extensionsLibPath := appendToAbsPath(envPath, extensionsLibFilename) + err = afero.WriteFile(m.appFS, string(extensionsLibPath), extensionsLibData, 0644) return err } @@ -184,12 +191,12 @@ func (m *manager) createAppDirTree() error { return nil } -func generateKsonnetLibData(ksonnetLibDir AbsPath, text []byte) ([]byte, error) { +func generateKsonnetLibData(ksonnetLibDir AbsPath, text []byte) ([]byte, []byte, error) { // Deserialize the API object. s := kubespec.APISpec{} err := json.Unmarshal(text, &s) if err != nil { - return nil, err + return nil, nil, err } s.Text = text diff --git a/metadata/manager_test.go b/metadata/manager_test.go index d88ed7e4..af011875 100644 --- a/metadata/manager_test.go +++ b/metadata/manager_test.go @@ -22,7 +22,7 @@ const ( "definitions": { } }` - blankKsonnetLib = `// AUTOGENERATED from the Kubernetes OpenAPI specification. DO NOT MODIFY. + blankK8sLib = `// AUTOGENERATED from the Kubernetes OpenAPI specification. DO NOT MODIFY. // Kubernetes version: v1.7.0 { @@ -79,12 +79,20 @@ func TestInitSuccess(t *testing.T) { t.Fatalf("Expected swagger file at '%s' to have value: '%s', got: '%s'", schemaPath, blankSwaggerData, actualSwagger) } - ksonnetLibPath := appendToAbsPath(envPath, ksonnetLibCoreFilename) - ksonnetLibBytes, err := afero.ReadFile(testFS, string(ksonnetLibPath)) + k8sLibPath := appendToAbsPath(envPath, k8sLibFilename) + k8sLibBytes, err := afero.ReadFile(testFS, string(k8sLibPath)) if err != nil { - t.Fatalf("Failed to read ksonnet-lib file at '%s':\n%v", ksonnetLibPath, err) - } else if actualKsonnetLib := string(ksonnetLibBytes); actualKsonnetLib != blankKsonnetLib { - t.Fatalf("Expected swagger file at '%s' to have value: '%s', got: '%s'", ksonnetLibPath, blankKsonnetLib, actualKsonnetLib) + t.Fatalf("Failed to read ksonnet-lib file at '%s':\n%v", k8sLibPath, err) + } else if actualK8sLib := string(k8sLibBytes); actualK8sLib != blankK8sLib { + t.Fatalf("Expected swagger file at '%s' to have value: '%s', got: '%s'", k8sLibPath, blankK8sLib, actualK8sLib) + } + + extensionsLibPath := appendToAbsPath(envPath, extensionsLibFilename) + extensionsLibBytes, err := afero.ReadFile(testFS, string(extensionsLibPath)) + if err != nil { + t.Fatalf("Failed to read ksonnet-lib file at '%s':\n%v", extensionsLibPath, err) + } else if string(extensionsLibBytes) == "" { + t.Fatalf("Expected extension library file at '%s' to be non-empty", extensionsLibPath) } } diff --git a/vendor/github.com/ksonnet/ksonnet-lib/ksonnet-gen/ksonnet/emit.go b/vendor/github.com/ksonnet/ksonnet-lib/ksonnet-gen/ksonnet/emit.go index 908ff43c..2b0b98c3 100644 --- a/vendor/github.com/ksonnet/ksonnet-lib/ksonnet-gen/ksonnet/emit.go +++ b/vendor/github.com/ksonnet/ksonnet-lib/ksonnet-gen/ksonnet/emit.go @@ -13,12 +13,19 @@ import ( // Emit takes a swagger API specification, and returns the text of // `ksonnet-lib`, written in Jsonnet. -func Emit(spec *kubespec.APISpec, ksonnetLibSHA, k8sSHA *string) ([]byte, error) { +func Emit(spec *kubespec.APISpec, ksonnetLibSHA, k8sSHA *string) ([]byte, []byte, error) { root := newRoot(spec, ksonnetLibSHA, k8sSHA) m := newIndentWriter() root.emit(m) - return m.bytes() + k8sBytes, err := m.bytes() + if err != nil { + return nil, nil, err + } + + kBytes := []byte(kubeversion.KSource(spec.Info.Version)) + + return kBytes, k8sBytes, nil } //----------------------------------------------------------------------------- diff --git a/vendor/github.com/ksonnet/ksonnet-lib/ksonnet-gen/kubeversion/data.go b/vendor/github.com/ksonnet/ksonnet-lib/ksonnet-gen/kubeversion/data.go index a455bebc..bd90e066 100644 --- a/vendor/github.com/ksonnet/ksonnet-lib/ksonnet-gen/kubeversion/data.go +++ b/vendor/github.com/ksonnet/ksonnet-lib/ksonnet-gen/kubeversion/data.go @@ -67,6 +67,9 @@ var versions = map[string]versionData{ "APIResourceList": "apiResourceList", "APIVersions": "apiVersions", "ServerAddressByClientCIDR": "serverAddressByClientCidr", + + // Collisions with Jsonnet keywords. + "local": "localStorage", }, constructorSpecs: map[string][]CustomConstructorSpec{ "io.k8s.kubernetes.pkg.api.v1.Container": []CustomConstructorSpec{ @@ -250,5 +253,86 @@ var versions = map[string]versionData{ // Misc. "io.k8s.kubernetes.pkg.apis.extensions.v1beta1.DaemonSetSpec": newPropertySet("templateGeneration"), }, + kSource: `local k8s = import "k8s.libsonnet"; + +local apps = k8s.apps; +local core = k8s.core; +local extensions = k8s.extensions; + +local hidden = { + mapContainers(f):: { + local podContainers = super.spec.template.spec.containers, + spec+: { + template+: { + spec+: { + // IMPORTANT: This overwrites the 'containers' field + // for this deployment. + containers: std.map(f, podContainers), + }, + }, + }, + }, + + mapContainersWithName(names, f) :: + local nameSet = + if std.type(names) == "array" + then std.set(names) + else std.set([names]); + local inNameSet(name) = std.length(std.setInter(nameSet, std.set([name]))) > 0; + self.mapContainers( + function(c) + if std.objectHas(c, "name") && inNameSet(c.name) + then f(c) + else c + ), +}; + +k8s + { + apps:: apps + { + v1beta1:: apps.v1beta1 + { + local v1beta1 = apps.v1beta1, + + daemonSet:: v1beta1.daemonSet + { + mapContainers(f):: hidden.mapContainers(f), + mapContainersWithName(names, f):: hidden.mapContainersWithName(names, f), + }, + + deployment:: v1beta1.deployment + { + mapContainers(f):: hidden.mapContainers(f), + mapContainersWithName(names, f):: hidden.mapContainersWithName(names, f), + }, + }, + }, + + core:: core + { + v1:: core.v1 + { + list:: { + new(items):: + {apiVersion: "v1"} + + {kind: "List"} + + self.items(items), + + items(items):: if std.type(items) == "array" then {items+: items} else {items+: [items]}, + }, + }, + }, + + extensions:: extensions + { + v1beta1:: extensions.v1beta1 + { + local v1beta1 = extensions.v1beta1, + + daemonSet:: v1beta1.daemonSet + { + mapContainers(f):: hidden.mapContainers(f), + mapContainersWithName(names, f):: hidden.mapContainersWithName(names, f), + }, + + deployment:: v1beta1.deployment + { + mapContainers(f):: hidden.mapContainers(f), + mapContainersWithName(names, f):: hidden.mapContainersWithName(names, f), + }, + }, + }, +} +`, }, } diff --git a/vendor/github.com/ksonnet/ksonnet-lib/ksonnet-gen/kubeversion/version.go b/vendor/github.com/ksonnet/ksonnet-lib/ksonnet-gen/kubeversion/version.go index f988fcfe..39467dee 100644 --- a/vendor/github.com/ksonnet/ksonnet-lib/ksonnet-gen/kubeversion/version.go +++ b/vendor/github.com/ksonnet/ksonnet-lib/ksonnet-gen/kubeversion/version.go @@ -15,6 +15,17 @@ import ( "github.com/ksonnet/ksonnet-lib/ksonnet-gen/kubespec" ) +// KSource returns the source of `k.libsonnet` for a specific version +// of Kubernetes. +func KSource(k8sVersion string) string { + verData, ok := versions[k8sVersion] + if !ok { + log.Fatalf("Unrecognized Kubernetes version '%s'", k8sVersion) + } + + return verData.kSource +} + // MapIdentifier takes a text identifier and maps it to a // Jsonnet-appropriate identifier, for some version of Kubernetes. For // example, in Kubernetes v1.7.0, we might map `clusterIP` -> @@ -75,6 +86,7 @@ type versionData struct { idAliases map[string]string constructorSpecs map[string][]CustomConstructorSpec propertyBlacklist map[string]propertySet + kSource string } type propertySet map[string]bool diff --git a/vendor/vendor.json b/vendor/vendor.json index a626c95f..54f12a54 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -211,26 +211,26 @@ { "checksumSHA1": "wX+GmcWpMzCIcxR9YtN1FCM9BEE=", "path": "github.com/ksonnet/ksonnet-lib/ksonnet-gen/jsonnet", - "revision": "fcf4c31408afc7b7469a1722c4cc06ccc315a722", - "revisionTime": "2017-08-16T22:14:57Z" + "revision": "b27d2d7778c12c3d762d24c1b9fd4c41da6c73c7", + "revisionTime": "2017-09-10T05:18:39Z" }, { - "checksumSHA1": "LGk0N301rp2uQSOmy7kBQEksues=", + "checksumSHA1": "zJx/j+IS6qd0P5h2m8WEQEtrACU=", "path": "github.com/ksonnet/ksonnet-lib/ksonnet-gen/ksonnet", - "revision": "fcf4c31408afc7b7469a1722c4cc06ccc315a722", - "revisionTime": "2017-08-16T22:14:57Z" + "revision": "b27d2d7778c12c3d762d24c1b9fd4c41da6c73c7", + "revisionTime": "2017-09-10T05:18:39Z" }, { "checksumSHA1": "BiiHRiYpSOb+vHiP6h/A9lRotEY=", "path": "github.com/ksonnet/ksonnet-lib/ksonnet-gen/kubespec", - "revision": "fcf4c31408afc7b7469a1722c4cc06ccc315a722", - "revisionTime": "2017-08-16T22:14:57Z" + "revision": "b27d2d7778c12c3d762d24c1b9fd4c41da6c73c7", + "revisionTime": "2017-09-10T05:18:39Z" }, { - "checksumSHA1": "jpBOSqq1T9UyiANimAKtzyTt3qo=", + "checksumSHA1": "lr+Bx7/N2KHk9dOrsWfLYBPjbdQ=", "path": "github.com/ksonnet/ksonnet-lib/ksonnet-gen/kubeversion", - "revision": "fcf4c31408afc7b7469a1722c4cc06ccc315a722", - "revisionTime": "2017-08-16T22:14:57Z" + "revision": "b27d2d7778c12c3d762d24c1b9fd4c41da6c73c7", + "revisionTime": "2017-09-10T05:18:39Z" }, { "checksumSHA1": "T8soMJArSZrYnhmdpAnq1bVxQ6Q=", -- GitLab