github.com/grafana/tanka@v0.26.1-0.20240506093700-c22cfc35c21a/pkg/tanka/static.go (about)

     1  package tanka
     2  
     3  import (
     4  	"encoding/json"
     5  
     6  	"github.com/grafana/tanka/pkg/jsonnet/implementations/types"
     7  	"github.com/grafana/tanka/pkg/spec"
     8  	"github.com/grafana/tanka/pkg/spec/v1alpha1"
     9  	"github.com/rs/zerolog/log"
    10  )
    11  
    12  // StaticLoader loads an environment from a static file called `spec.json`.
    13  // Jsonnet is evaluated as normal
    14  type StaticLoader struct {
    15  	jsonnetImpl types.JsonnetImplementation
    16  }
    17  
    18  func (s StaticLoader) Load(path string, opts LoaderOpts) (*v1alpha1.Environment, error) {
    19  	config, err := s.Peek(path, opts)
    20  	if err != nil {
    21  		return nil, err
    22  	}
    23  
    24  	data, err := s.Eval(path, opts)
    25  	if err != nil {
    26  		return nil, err
    27  	}
    28  	config.Data = data
    29  
    30  	return config, nil
    31  }
    32  
    33  func (s StaticLoader) Peek(path string, _ LoaderOpts) (*v1alpha1.Environment, error) {
    34  	config, err := parseStaticSpec(path)
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  
    39  	return config, nil
    40  }
    41  
    42  func (s StaticLoader) List(path string, opts LoaderOpts) ([]*v1alpha1.Environment, error) {
    43  	env, err := s.Peek(path, opts)
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  
    48  	return []*v1alpha1.Environment{env}, nil
    49  }
    50  
    51  func (s *StaticLoader) Eval(path string, opts LoaderOpts) (interface{}, error) {
    52  	config, err := s.Peek(path, opts)
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  
    57  	envCode, err := specToExtCode(config)
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  	opts.ExtCode.Set(environmentExtCode, envCode)
    62  
    63  	raw, err := evalJsonnet(path, s.jsonnetImpl, opts.JsonnetOpts)
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  
    68  	var data interface{}
    69  	if err := json.Unmarshal([]byte(raw), &data); err != nil {
    70  		return nil, err
    71  	}
    72  
    73  	return data, nil
    74  }
    75  
    76  func specToExtCode(spec *v1alpha1.Environment) (string, error) {
    77  	spec.Data = nil
    78  	data, err := json.Marshal(spec)
    79  	if err != nil {
    80  		return "", err
    81  	}
    82  
    83  	return string(data), nil
    84  }
    85  
    86  // parseStaticSpec parses the `spec.json` of the environment and returns a
    87  // *kubernetes.Kubernetes from it
    88  func parseStaticSpec(path string) (*v1alpha1.Environment, error) {
    89  	env, err := spec.ParseDir(path)
    90  	if err != nil {
    91  		switch err.(type) {
    92  		// the config includes deprecated fields
    93  		case spec.ErrDeprecated:
    94  			log.Warn().Err(err).Msg("encountered deprecated fields in spec.json")
    95  		// spec.json missing. we can still work with the default value
    96  		case spec.ErrNoSpec:
    97  			return env, nil
    98  		// some other error
    99  		default:
   100  			return nil, err
   101  		}
   102  	}
   103  
   104  	return env, nil
   105  }