Skip to content

Commit

Permalink
feat: inline Environment (#403)
Browse files Browse the repository at this point in the history
  • Loading branch information
Duologic authored Nov 26, 2020
1 parent 2033fc1 commit 12f7716
Show file tree
Hide file tree
Showing 19 changed files with 375 additions and 80 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
dist
tk
8 changes: 4 additions & 4 deletions cmd/tk/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func envCmd() *cli.Command {
return cmd
}

func envSettingsFlags(env *v1alpha1.Config, fs *pflag.FlagSet) {
func envSettingsFlags(env *v1alpha1.Environment, fs *pflag.FlagSet) {
fs.StringVar(&env.Spec.APIServer, "server", env.Spec.APIServer, "endpoint of the Kubernetes API")
fs.StringVar(&env.Spec.APIServer, "server-from-context", env.Spec.APIServer, "set the server to a known one from $KUBECONFIG")
fs.StringVar(&env.Spec.Namespace, "namespace", env.Spec.Namespace, "namespace to create objects in")
Expand All @@ -61,7 +61,7 @@ func envSetCmd() *cli.Command {
}

// flags
tmp := v1alpha1.Config{}
tmp := v1alpha1.Environment{}
envSettingsFlags(&tmp, cmd.Flags())

// removed name flag
Expand Down Expand Up @@ -136,7 +136,7 @@ func envAddCmd() *cli.Command {
}

// used by initCmd() as well
func addEnv(dir string, cfg *v1alpha1.Config) error {
func addEnv(dir string, cfg *v1alpha1.Environment) error {
path, err := filepath.Abs(dir)
if err != nil {
return err
Expand Down Expand Up @@ -216,7 +216,7 @@ func envListCmd() *cli.Command {
useNames := cmd.Flags().Bool("names", false, "plain names output")

cmd.Run = func(cmd *cli.Command, args []string) error {
envs := []v1alpha1.Config{}
envs := []v1alpha1.Environment{}
dirs := findBaseDirs()
var selector labels.Selector
var err error
Expand Down
2 changes: 1 addition & 1 deletion cmd/tk/jsonnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func evalCmd() *cli.Command {
jsonnetOpts.EvalPattern = *evalPattern
raw, err := tanka.Eval(args[0], jsonnetOpts)

if err != nil {
if raw == nil && err != nil {
return err
}

Expand Down
15 changes: 14 additions & 1 deletion cmd/tk/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

"github.com/go-clix/cli"

"github.com/grafana/tanka/pkg/jsonnet"
"github.com/grafana/tanka/pkg/jsonnet/jpath"
"github.com/grafana/tanka/pkg/spec"
"github.com/grafana/tanka/pkg/spec/v1alpha1"
Expand Down Expand Up @@ -60,7 +61,7 @@ func main() {
}
}

func setupConfiguration(baseDir string) *v1alpha1.Config {
func setupConfiguration(baseDir string) *v1alpha1.Environment {
_, baseDir, rootDir, err := jpath.Resolve(baseDir)
if err != nil {
log.Fatalln("Resolving jpath:", err)
Expand All @@ -77,6 +78,18 @@ func setupConfiguration(baseDir string) *v1alpha1.Config {
if verbose {
fmt.Print(err)
}
// no spec.json is found, try parsing main.jsonnet
case spec.ErrNoSpec:
config, err := tanka.EvalEnvs(baseDir, jsonnet.Opts{})
if err != nil {
switch err.(type) {
case tanka.ErrNoEnv:
return nil
default:
log.Fatalf("Reading main.jsonnet: %s", err)
}
}
return config
// some other error
default:
log.Fatalf("Reading spec.json: %s", err)
Expand Down
2 changes: 1 addition & 1 deletion cmd/tk/other.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func findBaseDirs() (dirs []string) {
}

if err := filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
requiredFiles := []string{"main.jsonnet", "spec.json"}
requiredFiles := []string{"main.jsonnet"}
for _, name := range requiredFiles {
if _, err := os.Stat(filepath.Join(path, name)); err != nil {
// missing file, not a valid environment directory
Expand Down
4 changes: 2 additions & 2 deletions pkg/kubernetes/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (

// Kubernetes exposes methods to work with the Kubernetes orchestrator
type Kubernetes struct {
Env v1alpha1.Config
Env v1alpha1.Environment

// Client (kubectl)
ctl client.Client
Expand All @@ -26,7 +26,7 @@ type Kubernetes struct {
type Differ func(manifest.List) (*string, error)

// New creates a new Kubernetes with an initialized client
func New(env v1alpha1.Config) (*Kubernetes, error) {
func New(env v1alpha1.Environment) (*Kubernetes, error) {
// setup client
ctl, err := client.New(env.Spec.APIServer)
if err != nil {
Expand Down
6 changes: 3 additions & 3 deletions pkg/process/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const (
// - tanka.dev/** labels
// - filtering
// - best-effort sorting
func Process(raw interface{}, cfg v1alpha1.Config, exprs Matchers) (manifest.List, error) {
func Process(raw interface{}, cfg v1alpha1.Environment, exprs Matchers) (manifest.List, error) {
// Scan for everything that looks like a Kubernetes object
extracted, err := Extract(raw)
if err != nil {
Expand Down Expand Up @@ -56,7 +56,7 @@ func Process(raw interface{}, cfg v1alpha1.Config, exprs Matchers) (manifest.Lis
}

// Label conditionally adds tanka.dev/** labels to each manifest in the List
func Label(list manifest.List, cfg v1alpha1.Config) manifest.List {
func Label(list manifest.List, cfg v1alpha1.Environment) manifest.List {
for i, m := range list {
// inject tanka.dev/environment label
if cfg.Spec.InjectLabels {
Expand All @@ -68,7 +68,7 @@ func Label(list manifest.List, cfg v1alpha1.Config) manifest.List {
return list
}

func ResourceDefaults(list manifest.List, cfg v1alpha1.Config) manifest.List {
func ResourceDefaults(list manifest.List, cfg v1alpha1.Environment) manifest.List {
for i, m := range list {
for k, v := range cfg.Spec.ResourceDefaults.Annotations {
annotations := m.Metadata().Annotations()
Expand Down
2 changes: 1 addition & 1 deletion pkg/process/resourceDefaults_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func TestResourceDefaults(t *testing.T) {

for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
cfg := v1alpha1.Config{
cfg := v1alpha1.Environment{
Spec: v1alpha1.Spec{
ResourceDefaults: v1alpha1.ResourceDefaults{
Annotations: c.specAnnotations,
Expand Down
5 changes: 4 additions & 1 deletion pkg/spec/depreciations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import (
func TestDeprecated(t *testing.T) {
data := []byte(`
{
"metadata": {
"name": "test"
},
"spec": {
"namespace": "new"
},
Expand All @@ -23,7 +26,7 @@ func TestDeprecated(t *testing.T) {
}
`)

got, err := Parse(data, "test")
got, err := Parse(data)
require.Equal(t, ErrDeprecated{
{old: "server", new: "spec.apiServer"},
{old: "team", new: "metadata.labels.team"},
Expand Down
22 changes: 12 additions & 10 deletions pkg/spec/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ const APIGroup = "tanka.dev"
// Specfile is the filename for the environment config
const Specfile = "spec.json"

// ParseDir parses the given environments `spec.json` into a `v1alpha1.Config`
// ParseDir parses the given environments `spec.json` into a `v1alpha1.Environment`
// object with the name set to the directories name
func ParseDir(baseDir, name string) (*v1alpha1.Config, error) {
func ParseDir(baseDir, name string) (*v1alpha1.Environment, error) {
fi, err := os.Stat(baseDir)
if err != nil {
return nil, err
Expand All @@ -39,20 +39,22 @@ func ParseDir(baseDir, name string) (*v1alpha1.Config, error) {
return nil, err
}

return Parse(data, name)
c, err := Parse(data)
if c != nil {
// set the name field
c.Metadata.Name = name
}

return c, err
}

// Parse parses the json `data` into a `v1alpha1.Config` object.
// `name` is the name of the environment
func Parse(data []byte, name string) (*v1alpha1.Config, error) {
// Parse parses the json `data` into a `v1alpha1.Environment` object.
func Parse(data []byte) (*v1alpha1.Environment, error) {
config := v1alpha1.New()
if err := json.Unmarshal(data, config); err != nil {
return nil, errors.Wrap(err, "parsing spec.json")
}

// set the name field
config.Metadata.Name = name

if err := handleDeprecated(config, data); err != nil {
return config, err
}
Expand All @@ -65,7 +67,7 @@ func Parse(data []byte, name string) (*v1alpha1.Config, error) {
return config, nil
}

func handleDeprecated(c *v1alpha1.Config, data []byte) error {
func handleDeprecated(c *v1alpha1.Environment, data []byte) error {
var errDepr ErrDeprecated

var msi map[string]interface{}
Expand Down
20 changes: 10 additions & 10 deletions pkg/spec/v1alpha1/config.go → pkg/spec/v1alpha1/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ package v1alpha1

import "strings"

// New creates a new Config object with internal values already set
func New() *Config {
c := Config{}
// New creates a new Environment object with internal values already set
func New() *Environment {
c := Environment{}

// constants
c.APIVersion = "tanka.dev/v1alpha1"
Expand All @@ -18,13 +18,13 @@ func New() *Config {
return &c
}

// Config holds the configuration variables for config version v1alpha1
// ApiVersion and Kind are currently unused, this may change in the future.
type Config struct {
APIVersion string `json:"apiVersion"`
Kind string `json:"kind"`
Metadata Metadata `json:"metadata"`
Spec Spec `json:"spec"`
// Environment represents a set of resources in relation to its Kubernetes cluster
type Environment struct {
APIVersion string `json:"apiVersion"`
Kind string `json:"kind"`
Metadata Metadata `json:"metadata"`
Spec Spec `json:"spec"`
Data interface{} `json:"data,omitempty"`
}

// Metadata is meant for humans and not parsed
Expand Down
26 changes: 26 additions & 0 deletions pkg/tanka/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package tanka

import (
"fmt"
"strings"
)

// ErrNoEnv means that the given jsonnet has no Environment object
// This must not be fatal, some operations work without
type ErrNoEnv struct {
path string
}

func (e ErrNoEnv) Error() string {
return fmt.Sprintf("unable to find an Environment in '%s'", e.path)
}

// ErrMultipleEnvs means that the given jsonnet has multiple Environment objects
type ErrMultipleEnvs struct {
path string
names []string
}

func (e ErrMultipleEnvs) Error() string {
return fmt.Sprintf("found multiple Environments (%s) in '%s'", strings.Join(e.names, ", "), e.path)
}
Loading

0 comments on commit 12f7716

Please sign in to comment.