mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-11 17:12:51 +00:00
Check for cycles during create-subst
This commit is contained in:
@@ -5,12 +5,16 @@ package settersutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/spec"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/fieldmeta"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/openapi"
|
||||
"sigs.k8s.io/kustomize/kyaml/sets"
|
||||
"sigs.k8s.io/kustomize/kyaml/setters2"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
@@ -47,7 +51,15 @@ func (c SubstitutionCreator) Create(openAPIPath, resourcesPath string) error {
|
||||
Pattern: c.Pattern,
|
||||
}
|
||||
|
||||
err := c.CreateSettersForSubstitution(openAPIPath)
|
||||
// the input substitution definition is updated in the openAPI file and then parsed
|
||||
// to check if there are any cycles in nested substitutions, if there are
|
||||
// any, the openAPI file will be reverted to current state and error is thrown
|
||||
stat, err := os.Stat(openAPIPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
curOpenAPI, err := ioutil.ReadFile(openAPIPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -61,6 +73,40 @@ func (c SubstitutionCreator) Create(openAPIPath, resourcesPath string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
visited := sets.String{}
|
||||
ref, err := spec.NewRef(fieldmeta.DefinitionsPrefix + fieldmeta.SubstitutionDefinitionPrefix + c.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
schema, err := openapi.Resolve(&ref)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ext, err := setters2.GetExtFromSchema(schema)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = c.CreateSettersForSubstitution(openAPIPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Load the updated definitions after setters are created
|
||||
if err := openapi.AddSchemaFromFile(openAPIPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// revert openAPI file if there are cycles detected in created input substitution
|
||||
if err := checkForCycles(ext, visited); err != nil {
|
||||
if writeErr := ioutil.WriteFile(openAPIPath, curOpenAPI, stat.Mode().Perm()); writeErr != nil {
|
||||
return writeErr
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Update the resources with the setter reference
|
||||
inout := &kio.LocalPackageReadWriter{PackagePath: resourcesPath}
|
||||
return kio.Pipeline{
|
||||
@@ -77,7 +123,7 @@ func (c SubstitutionCreator) Create(openAPIPath, resourcesPath string) error {
|
||||
|
||||
// CreateSettersForSubstitution creates the setters for all the references in the substitution
|
||||
// values if they don't already exist in openAPIPath file.
|
||||
func (c *SubstitutionCreator) CreateSettersForSubstitution(openAPIPath string) error {
|
||||
func (c SubstitutionCreator) CreateSettersForSubstitution(openAPIPath string) error {
|
||||
y, err := yaml.ReadFile(openAPIPath)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -88,9 +134,14 @@ func (c *SubstitutionCreator) CreateSettersForSubstitution(openAPIPath string) e
|
||||
return err
|
||||
}
|
||||
|
||||
// for each ref in values, check if the setter already exists, if not create them
|
||||
for i := range c.Values {
|
||||
value := c.Values[i]
|
||||
// for each ref in values, check if the setter or substitution already exists, if not create setter
|
||||
for _, value := range c.Values {
|
||||
// continue if ref is a substitution, as it has already been checked if it exists
|
||||
// as part of preRunE
|
||||
if strings.Contains(value.Ref, fieldmeta.SubstitutionDefinitionPrefix) {
|
||||
fmt.Printf("found a substitution with name %s\n", value.Marker)
|
||||
continue
|
||||
}
|
||||
setterObj, err := y.Pipe(yaml.Lookup(
|
||||
// get the setter key from ref. Ex: from #/definitions/io.k8s.cli.setters.image_setter
|
||||
// extract io.k8s.cli.setters.image_setter
|
||||
@@ -100,22 +151,7 @@ func (c *SubstitutionCreator) CreateSettersForSubstitution(openAPIPath string) e
|
||||
return err
|
||||
}
|
||||
|
||||
arr := strings.Split(value.Ref, ".")
|
||||
name := arr[len(arr)-1]
|
||||
// lookup if there is a substitution with name as it could be a nested substitution
|
||||
substRef := fieldmeta.SubstitutionDefinitionPrefix + name
|
||||
substObj, err := y.Pipe(yaml.Lookup("openAPI", "definitions", substRef))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if setterObj == nil && substObj != nil {
|
||||
fmt.Printf("found a substitution with name %s\n", name)
|
||||
c.Values[i].Ref = fieldmeta.DefinitionsPrefix + substRef
|
||||
}
|
||||
|
||||
if setterObj == nil && substObj == nil {
|
||||
if setterObj == nil {
|
||||
name := strings.TrimPrefix(value.Ref, fieldmeta.DefinitionsPrefix+fieldmeta.SetterDefinitionPrefix)
|
||||
value := m[value.Marker]
|
||||
fmt.Printf("unable to find setter with name %s, creating new setter with value %s\n", name, value)
|
||||
@@ -134,6 +170,49 @@ func (c *SubstitutionCreator) CreateSettersForSubstitution(openAPIPath string) e
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkForCycles(ext *setters2.CliExtension, visited sets.String) error {
|
||||
// check if the substitution has already been visited and throw error as cycles
|
||||
// are not allowed in nested substitutions
|
||||
if visited.Has(ext.Substitution.Name) {
|
||||
return errors.Errorf(
|
||||
"cyclic substitution detected with name " + ext.Substitution.Name)
|
||||
}
|
||||
|
||||
visited.Insert(ext.Substitution.Name)
|
||||
|
||||
// substitute each setter into the pattern to get the new value
|
||||
// if substitution references to another substitution, recursively
|
||||
// process the nested substitutions to replace the pattern with setter values
|
||||
for _, v := range ext.Substitution.Values {
|
||||
if v.Ref == "" {
|
||||
return errors.Errorf(
|
||||
"missing reference on substitution " + ext.Substitution.Name)
|
||||
}
|
||||
ref, err := spec.NewRef(v.Ref)
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
def, err := openapi.Resolve(&ref) // resolve the def to its openAPI def
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
defExt, err := setters2.GetExtFromSchema(def) // parse the extension out of the openAPI
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
|
||||
if defExt.Substitution != nil {
|
||||
// parse recursively if it reference is substitution
|
||||
err := checkForCycles(defExt, visited)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetValuesForMarkers parses the pattern and field value to derive values for the
|
||||
// markers in the pattern string. Returns error if the marker values can't be derived
|
||||
func (c SubstitutionCreator) GetValuesForMarkers() (map[string]string, error) {
|
||||
|
||||
Reference in New Issue
Block a user