Skip to content
Snippets Groups Projects
Commit 98c7428f authored by Alex Clemmer's avatar Alex Clemmer
Browse files

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.
parent 7217fdc8
No related branches found
No related tags found
No related merge requests found
......@@ -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
......
......@@ -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)
}
}
......
......@@ -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
}
//-----------------------------------------------------------------------------
......
......@@ -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),
},
},
},
}
`,
},
}
......@@ -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
......
......@@ -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=",
......
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