Skip to content

Commit

Permalink
Simple Kubernetes CRD-based frontend 🦉 for EnvSpecDefs & Resolution P…
Browse files Browse the repository at this point in the history
…ath (#696)

Unlocking the simple CRD kinds `EnvSpecDefinitions` & `EnvResolution`.
  • Loading branch information
sourishkrout authored Nov 5, 2024
1 parent cf68547 commit e564797
Show file tree
Hide file tree
Showing 13 changed files with 345 additions and 149 deletions.
2 changes: 0 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: check-yaml
stages: [pre-commit]
- id: check-json
exclude: "^.vscode/"
stages: [pre-commit]
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ func printStore(cmd *cobra.Command, msgData *runnerv1.MonitorEnvStoreResponse_Sn
table.EndRow()

specless := true
for i, _ := range msgData.Snapshot.Envs {
for i := range msgData.Snapshot.Envs {
backwards := msgData.Snapshot.Envs[len(msgData.Snapshot.Envs)-i-1]
if backwards.Spec != owl.AtomicNameOpaque {
specless = false
Expand Down
2 changes: 1 addition & 1 deletion internal/owl/envSpecDefs.defaults.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
apiVersion: runme.stateful.com/v1beta1
apiVersion: runme.stateful.com/v1alpha1
kind: EnvSpecDefinitions
metadata:
name: runme
Expand Down
121 changes: 69 additions & 52 deletions internal/owl/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ var (
)

var EnvironmentType,
EnvSpecsType,
ValidateType,
ResolveType,
RenderType,
Expand Down Expand Up @@ -1328,6 +1329,9 @@ func init() {
"breaker": &graphql.InputObjectFieldConfig{
Type: graphql.String,
},
"origin": &graphql.InputObjectFieldConfig{
Type: graphql.String,
},
"atomics": &graphql.InputObjectFieldConfig{
Type: graphql.NewList(graphql.NewInputObject(graphql.InputObjectConfig{
Name: "AtomicEnvSpecInputType",
Expand All @@ -1350,6 +1354,69 @@ func init() {
},
})

EnvSpecsType = graphql.NewObject(graphql.ObjectConfig{
Name: "EnvSpecsType",
Fields: (graphql.FieldsThunk)(func() graphql.Fields {
return graphql.Fields{
"definitions": &graphql.Field{
Type: graphql.NewList(
graphql.NewObject(graphql.ObjectConfig{
Name: "EnvSpecsDefType",
Fields: graphql.Fields{
"name": &graphql.Field{
Type: graphql.String,
},
"breaker": &graphql.Field{
Type: graphql.String,
},
"origin": &graphql.Field{
Type: graphql.String,
},
"atomics": &graphql.Field{
Type: graphql.NewList(graphql.NewObject(graphql.ObjectConfig{
Name: "AtomicEnvSpecsDefType",
Fields: graphql.Fields{
"key": &graphql.Field{
Type: graphql.String,
},
"atomic": &graphql.Field{
Type: graphql.String,
},
"rules": &graphql.Field{
Type: graphql.String,
},
"required": &graphql.Field{
Type: graphql.Boolean,
},
},
})),
},
},
}),
),
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return p.Source, nil
},
},
"load": &graphql.Field{
Type: EnvSpecsType,
Args: graphql.FieldConfigArgument{
"definitions": &graphql.ArgumentConfig{
Type: graphql.NewList(EnvSpecInputType),
},
},
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
defs, ok := p.Args["definitions"].([]interface{})
if !ok {
return nil, errors.New("definitions not found")
}
return defs, nil
},
},
}
}),
})

var err error
Schema, err = graphql.NewSchema(graphql.SchemaConfig{
Query: graphql.NewObject(
Expand All @@ -1363,59 +1430,9 @@ func init() {
},
},
"EnvSpecs": &graphql.Field{
Type: graphql.NewObject(graphql.ObjectConfig{
Name: "EnvSpecsType",
Fields: graphql.Fields{
"definitions": &graphql.Field{
Type: graphql.NewList(
graphql.NewObject(graphql.ObjectConfig{
Name: "EnvSpecsDefType",
Fields: graphql.Fields{
"name": &graphql.Field{
Type: graphql.String,
},
"breaker": &graphql.Field{
Type: graphql.String,
},
"atomics": &graphql.Field{
Type: graphql.NewList(graphql.NewObject(graphql.ObjectConfig{
Name: "AtomicEnvSpecsDefType",
Fields: graphql.Fields{
"key": &graphql.Field{
Type: graphql.String,
},
"atomic": &graphql.Field{
Type: graphql.String,
},
"rules": &graphql.Field{
Type: graphql.String,
},
"required": &graphql.Field{
Type: graphql.Boolean,
},
},
})),
},
},
}),
),
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return p.Source, nil
},
},
},
}),
Args: graphql.FieldConfigArgument{
"definitions": &graphql.ArgumentConfig{
Type: graphql.NewList(EnvSpecInputType),
},
},
Type: EnvSpecsType,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
defs, ok := p.Args["definitions"].([]interface{})
if !ok {
return nil, errors.New("definitions not found")
}
return defs, nil
return p.Info.FieldName, nil
},
},
"Atomics": &graphql.Field{
Expand Down
123 changes: 64 additions & 59 deletions internal/owl/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func (s *Store) snapshotQuery(query, vars io.StringWriter, resolve bool) error {

if resolve {
reducers = append(reducers, []QueryNodeReducer{
reduceWrapResolve(),
reduceWrapResolve(s),
reduceWrapDone(),
reduceWrapValidate(),
reduceAtomic("", nil),
Expand All @@ -78,7 +78,7 @@ func (s *Store) snapshotQuery(query, vars io.StringWriter, resolve bool) error {
if resolve {
queryName = "Resolve"
}
q, err := s.NewEnvironmentQuery(queryName, varDefs,
q, err := s.NewQuery(queryName, "Environment", varDefs,
reducers,
)
if err != nil {
Expand Down Expand Up @@ -113,8 +113,9 @@ func (s *Store) defineEnvSpecDefsQuery(query io.StringWriter) error {
}),
}),
}
q, err := s.NewEnvSpecsQuery(
q, err := s.NewQuery(
"EnvSpecsDef",
"EnvSpecs",
varDefs,
[]QueryNodeReducer{
func(opSets []*OperationSet, opDef *ast.OperationDefinition, selSet *ast.SelectionSet) (*ast.SelectionSet, error) {
Expand All @@ -130,6 +131,11 @@ func (s *Store) defineEnvSpecDefsQuery(query io.StringWriter) error {
Value: "breaker",
}),
}),
ast.NewField(&ast.Field{
Name: ast.NewName(&ast.Name{
Value: "origin",
}),
}),
ast.NewField(&ast.Field{
Name: ast.NewName(&ast.Name{
Value: "atomics",
Expand Down Expand Up @@ -163,9 +169,30 @@ func (s *Store) defineEnvSpecDefsQuery(query io.StringWriter) error {
})
selSet.Selections = append(selSet.Selections, ast.NewField(&ast.Field{
Name: ast.NewName(&ast.Name{
Value: "definitions",
Value: "load",
}),
Arguments: []*ast.Argument{
ast.NewArgument(&ast.Argument{
Name: ast.NewName(&ast.Name{
Value: "definitions",
}),
Value: ast.NewVariable(&ast.Variable{
Name: ast.NewName(&ast.Name{
Value: "definitions",
}),
}),
}),
},
SelectionSet: ast.NewSelectionSet(&ast.SelectionSet{
Selections: []ast.Selection{
ast.NewField(&ast.Field{
Name: ast.NewName(&ast.Name{
Value: "definitions",
}),
SelectionSet: nextSelSet,
}),
},
}),
SelectionSet: nextSelSet,
}))
return nil, nil
},
Expand Down Expand Up @@ -207,7 +234,7 @@ func (s *Store) sensitiveKeysQuery(query, vars io.StringWriter) error {
}),
}

q, err := s.NewEnvironmentQuery("Sensitive", varDefs,
q, err := s.NewQuery("Sensitive", "Environment", varDefs,
[]QueryNodeReducer{
reconcileAsymmetry(s),
reduceSetOperations(vars),
Expand Down Expand Up @@ -286,7 +313,7 @@ func (s *Store) getterQuery(query, vars io.StringWriter) error {
}
s.logger.Debug("getter opSets breakdown", zap.Int("loaded", loaded), zap.Int("updated", updated), zap.Int("deleted", deleted), zap.Int("total", len(s.opSets)))

q, err := s.NewEnvironmentQuery("Get", varDefs,
q, err := s.NewQuery("Get", "Environment", varDefs,
[]QueryNodeReducer{
reconcileAsymmetry(s),
reduceSetOperations(vars),
Expand Down Expand Up @@ -314,7 +341,28 @@ func (s *Store) getterQuery(query, vars io.StringWriter) error {
return nil
}

func reduceWrapResolve() QueryNodeReducer {
func reduceWrapResolve(store *Store) QueryNodeReducer {
exprVal := `key | lower()`
projectVal := "dev"

// todo(sebastian): we should traverse the path and gen the query
if store.resolvePath != nil {
if t, err := extractDataKey(store.resolvePath, "transform"); err == nil {
if expr, err := extractDataKey(t, "expr"); err == nil {
exprVal = expr.(string)
}
if gcp, err := extractDataKey(t, "gcp"); err == nil {
if auth, err := extractDataKey(gcp, "auth"); err == nil {
if v, ok := auth.(string); !ok || v != "ADC" {
return nil
}
}
if project, err := extractDataKey(gcp, "project"); err == nil {
projectVal = project.(string)
}
}
}
}
return func(opSets []*OperationSet, opDef *ast.OperationDefinition, selSet *ast.SelectionSet) (*ast.SelectionSet, error) {
resolveSelSet := ast.NewSelectionSet(&ast.SelectionSet{
Selections: []ast.Selection{
Expand Down Expand Up @@ -350,7 +398,7 @@ func reduceWrapResolve() QueryNodeReducer {
Value: "project",
}),
Value: ast.NewStringValue(&ast.StringValue{
Value: "platform-staging-413816",
Value: projectVal,
}),
}),
},
Expand All @@ -366,7 +414,7 @@ func reduceWrapResolve() QueryNodeReducer {
Value: "expr",
}),
Value: ast.NewStringValue(&ast.StringValue{
Value: `key | trimPrefix("REDWOOD_ENV_") | replace("SLACK_REDIRECT_URL", "SLACK_REDIRECT") | lower()`,
Value: exprVal,
}),
}),
},
Expand Down Expand Up @@ -1301,65 +1349,19 @@ type Query struct {
doc *ast.Document
}

func (s *Store) NewEnvSpecsQuery(name string, varDefs []*ast.VariableDefinition, reducers []QueryNodeReducer) (*Query, error) {
func (s *Store) NewQuery(queryName, rootSelelection string, varDefs []*ast.VariableDefinition, reducers []QueryNodeReducer) (*Query, error) {
selSet := ast.NewSelectionSet(&ast.SelectionSet{})
opDef := ast.NewOperationDefinition(&ast.OperationDefinition{
Operation: "query",
Name: ast.NewName(&ast.Name{
Value: fmt.Sprintf("Owl%s", name),
Value: fmt.Sprintf("Owl%s", queryName),
}),
Directives: []*ast.Directive{},
SelectionSet: ast.NewSelectionSet(&ast.SelectionSet{
Selections: []ast.Selection{
ast.NewField(&ast.Field{
Name: ast.NewName(&ast.Name{
Value: "EnvSpecs",
}),
Arguments: []*ast.Argument{
ast.NewArgument(&ast.Argument{
Name: ast.NewName(&ast.Name{
Value: "definitions",
}),
Value: ast.NewVariable(&ast.Variable{
Name: ast.NewName(&ast.Name{
Value: "definitions",
}),
}),
}),
},
Directives: []*ast.Directive{},
SelectionSet: selSet,
}),
},
}),
VariableDefinitions: varDefs,
})

var err error
for _, reducer := range reducers {
if selSet, err = reducer(s.opSets, opDef, selSet); err != nil {
return nil, err
}
}

doc := ast.NewDocument(&ast.Document{Definitions: []ast.Node{opDef}})

return &Query{doc: doc}, nil
}

func (s *Store) NewEnvironmentQuery(name string, varDefs []*ast.VariableDefinition, reducers []QueryNodeReducer) (*Query, error) {
selSet := ast.NewSelectionSet(&ast.SelectionSet{})
opDef := ast.NewOperationDefinition(&ast.OperationDefinition{
Operation: "query",
Name: ast.NewName(&ast.Name{
Value: fmt.Sprintf("Owl%s", name),
}),
Directives: []*ast.Directive{},
SelectionSet: ast.NewSelectionSet(&ast.SelectionSet{
Selections: []ast.Selection{
ast.NewField(&ast.Field{
Name: ast.NewName(&ast.Name{
Value: "Environment",
Value: rootSelelection,
}),
Arguments: []*ast.Argument{},
Directives: []*ast.Directive{},
Expand All @@ -1372,6 +1374,9 @@ func (s *Store) NewEnvironmentQuery(name string, varDefs []*ast.VariableDefiniti

var err error
for _, reducer := range reducers {
if reducer == nil {
continue
}
if selSet, err = reducer(s.opSets, opDef, selSet); err != nil {
return nil, err
}
Expand Down
Loading

0 comments on commit e564797

Please sign in to comment.