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

Emit `app.yaml` after init

When the user calls `ks init <whatever>`, we need to emit an `app.yaml`
for the new project. This commit will introduce such behavior.
parent 78bfa356
No related branches found
No related tags found
No related merge requests found
......@@ -70,7 +70,7 @@ var initCmd = &cobra.Command{
return err
}
c, err := kubecfg.NewInitCmd(appRoot, specFlag, &uri, &namespace)
c, err := kubecfg.NewInitCmd(appName, appRoot, specFlag, &uri, &namespace)
if err != nil {
return err
}
......@@ -112,7 +112,7 @@ consists of two steps:
# Initialize ksonnet application, using an OpenAPI specification file
# generated by a build of Kubernetes to generate 'ksonnet-lib'.
ks init app-name --api-spec=file:swagger.json
# Initialize ksonnet application, using the context 'dev' from the kubeconfig
# file.
ks init app-name --context=dev`,
......
......@@ -46,7 +46,7 @@ func mockEnvironments(t *testing.T, appName string) *manager {
}
appPath := AbsPath(appName)
m, err := initManager(appPath, spec, &mockAPIServer, &mockNamespace, testFS)
m, err := initManager(appName, appPath, spec, &mockAPIServer, &mockNamespace, testFS)
if err != nil {
t.Fatalf("Failed to init cluster spec: %v", err)
}
......
......@@ -78,8 +78,8 @@ func Find(path AbsPath) (Manager, error) {
// Init will retrieve a cluster API specification, generate a
// capabilities-compliant version of ksonnet-lib, and then generate the
// directory tree for an application.
func Init(rootPath AbsPath, spec ClusterSpec, serverURI, namespace *string) (Manager, error) {
return initManager(rootPath, spec, serverURI, namespace, appFS)
func Init(name string, rootPath AbsPath, spec ClusterSpec, serverURI, namespace *string) (Manager, error) {
return initManager(name, rootPath, spec, serverURI, namespace, appFS)
}
// ClusterSpec represents the API supported by some cluster. There are several
......
......@@ -16,6 +16,7 @@
package metadata
import (
"encoding/json"
"fmt"
"os"
"os/user"
......@@ -23,6 +24,7 @@ import (
"path/filepath"
"strings"
"github.com/ksonnet/ksonnet/metadata/app"
param "github.com/ksonnet/ksonnet/metadata/params"
"github.com/ksonnet/ksonnet/prototype"
log "github.com/sirupsen/logrus"
......@@ -43,6 +45,7 @@ const (
componentParamsFile = "params.libsonnet"
baseLibsonnetFile = "base.libsonnet"
appYAMLFile = "app.yaml"
// ComponentsExtCodeKey is the ExtCode key for component imports
ComponentsExtCodeKey = "__ksonnet/components"
......@@ -63,10 +66,11 @@ type manager struct {
libPath AbsPath
componentsPath AbsPath
environmentsPath AbsPath
vendorDir AbsPath
vendorPath AbsPath
componentParamsPath AbsPath
baseLibsonnetPath AbsPath
appYAMLPath AbsPath
// User-level paths.
userKsonnetRootPath AbsPath
......@@ -95,7 +99,7 @@ func findManager(abs AbsPath, appFS afero.Fs) (*manager, error) {
}
}
func initManager(rootPath AbsPath, spec ClusterSpec, serverURI, namespace *string, appFS afero.Fs) (*manager, error) {
func initManager(name string, rootPath AbsPath, spec ClusterSpec, serverURI, namespace *string, appFS afero.Fs) (*manager, error) {
m, err := newManager(rootPath, appFS)
if err != nil {
return nil, err
......@@ -114,7 +118,7 @@ func initManager(rootPath AbsPath, spec ClusterSpec, serverURI, namespace *strin
}
// Initialize directory structure.
if err := m.createAppDirTree(); err != nil {
if err := m.createAppDirTree(name); err != nil {
return nil, err
}
......@@ -150,10 +154,11 @@ func newManager(rootPath AbsPath, appFS afero.Fs) (*manager, error) {
libPath: appendToAbsPath(rootPath, libDir),
componentsPath: appendToAbsPath(rootPath, componentsDir),
environmentsPath: appendToAbsPath(rootPath, environmentsDir),
vendorDir: appendToAbsPath(rootPath, vendorDir),
vendorPath: appendToAbsPath(rootPath, vendorDir),
componentParamsPath: appendToAbsPath(rootPath, componentsDir, componentParamsFile),
baseLibsonnetPath: appendToAbsPath(rootPath, environmentsDir, baseLibsonnetFile),
appYAMLPath: appendToAbsPath(rootPath, appYAMLFile),
// User-level paths.
userKsonnetRootPath: userRootPath,
......@@ -270,7 +275,7 @@ func (m *manager) createUserDirTree() error {
return nil
}
func (m *manager) createAppDirTree() error {
func (m *manager) createAppDirTree(name string) error {
exists, err := afero.DirExists(m.appFS, string(m.rootPath))
if err != nil {
return fmt.Errorf("Could not check existance of directory '%s':\n%v", m.rootPath, err)
......@@ -284,7 +289,7 @@ func (m *manager) createAppDirTree() error {
m.libPath,
m.componentsPath,
m.environmentsPath,
m.vendorDir,
m.vendorPath,
}
for _, p := range dirPaths {
......@@ -293,6 +298,11 @@ func (m *manager) createAppDirTree() error {
}
}
appYAML, err := genAppYAMLContent(name)
if err != nil {
return err
}
filePaths := []struct {
path AbsPath
content []byte
......@@ -305,6 +315,10 @@ func (m *manager) createAppDirTree() error {
m.baseLibsonnetPath,
genBaseLibsonnetContent(),
},
{
m.appYAMLPath,
appYAML,
},
}
for _, f := range filePaths {
......@@ -344,6 +358,17 @@ func genComponentParamsContent() []byte {
`)
}
func genAppYAMLContent(name string) ([]byte, error) {
content := app.Spec{
APIVersion: app.DefaultAPIVersion,
Kind: app.Kind,
Name: name,
Version: app.DefaultVersion,
}
return json.MarshalIndent(&content, "", " ")
}
func genBaseLibsonnetContent() []byte {
return []byte(`local components = std.extVar("` + ComponentsExtCodeKey + `");
components + {
......
......@@ -61,7 +61,7 @@ func TestInitSuccess(t *testing.T) {
}
appPath := AbsPath("/fromEmptySwagger")
_, err = initManager(appPath, spec, &mockAPIServer, &mockNamespace, testFS)
_, err = initManager("fromEmptySwagger", appPath, spec, &mockAPIServer, &mockNamespace, testFS)
if err != nil {
t.Fatalf("Failed to init cluster spec: %v", err)
}
......@@ -150,6 +150,14 @@ func TestInitSuccess(t *testing.T) {
} else if len(baseLibsonnetBytes) == 0 {
t.Fatalf("Expected base.libsonnet at '%s' to be non-empty", baseLibsonnetPath)
}
appYAMLPath := appendToAbsPath(appPath, appYAMLFile)
appYAMLBytes, err := afero.ReadFile(testFS, string(appYAMLPath))
if err != nil {
t.Fatalf("Failed to read app.yaml file at '%s':\n%v", appYAMLPath, err)
} else if len(appYAMLBytes) == 0 {
t.Fatalf("Expected app.yaml at '%s' to be non-empty", appYAMLPath)
}
}
func TestFindSuccess(t *testing.T) {
......@@ -168,7 +176,7 @@ func TestFindSuccess(t *testing.T) {
}
appPath := AbsPath("/findSuccess")
_, err = initManager(appPath, spec, &mockAPIServer, &mockNamespace, testFS)
_, err = initManager("findSuccess", appPath, spec, &mockAPIServer, &mockNamespace, testFS)
if err != nil {
t.Fatalf("Failed to init cluster spec: %v", err)
}
......@@ -196,7 +204,7 @@ func TestComponentPaths(t *testing.T) {
}
appPath := AbsPath("/componentPaths")
m, err := initManager(appPath, spec, &mockAPIServer, &mockNamespace, testFS)
m, err := initManager("componentPaths", appPath, spec, &mockAPIServer, &mockNamespace, testFS)
if err != nil {
t.Fatalf("Failed to init cluster spec: %v", err)
}
......@@ -286,13 +294,13 @@ func TestDoubleNewFailure(t *testing.T) {
appPath := AbsPath("/doubleNew")
_, err = initManager(appPath, spec, &mockAPIServer, &mockNamespace, testFS)
_, err = initManager("doubleNew", appPath, spec, &mockAPIServer, &mockNamespace, 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, &mockAPIServer, &mockNamespace, testFS)
_, err = initManager("doubleNew", appPath, spec, &mockAPIServer, &mockNamespace, testFS)
if err == nil || err.Error() != targetErr {
t.Fatalf("Expected to fail to create app with message '%s', got '%s'", targetErr, err.Error())
}
......
......@@ -3,13 +3,14 @@ package kubecfg
import "github.com/ksonnet/ksonnet/metadata"
type InitCmd struct {
name string
rootPath metadata.AbsPath
spec metadata.ClusterSpec
serverURI *string
namespace *string
}
func NewInitCmd(rootPath metadata.AbsPath, specFlag string, serverURI, namespace *string) (*InitCmd, error) {
func NewInitCmd(name string, rootPath metadata.AbsPath, specFlag string, serverURI, namespace *string) (*InitCmd, error) {
// NOTE: We're taking `rootPath` here as an absolute path (rather than a partial path we expand to an absolute path)
// to make it more testable.
......@@ -18,10 +19,10 @@ func NewInitCmd(rootPath metadata.AbsPath, specFlag string, serverURI, namespace
return nil, err
}
return &InitCmd{rootPath: rootPath, spec: spec, serverURI: serverURI, namespace: namespace}, nil
return &InitCmd{name: name, rootPath: rootPath, spec: spec, serverURI: serverURI, namespace: namespace}, nil
}
func (c *InitCmd) Run() error {
_, err := metadata.Init(c.rootPath, c.spec, c.serverURI, c.namespace)
_, err := metadata.Init(c.name, c.rootPath, c.spec, c.serverURI, c.namespace)
return err
}
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