Skip to content
Snippets Groups Projects
Commit 394dea5d authored by Alex Clemmer's avatar Alex Clemmer Committed by GitHub
Browse files

Merge pull request #121 from hausdorff/fix-113

Fix #113
parents 7217fdc8 98c7428f
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