github.com/splunk/qbec@v0.15.2/vm/internal/natives/nativefuncs.go (about)

     1  // Copyright 2017 The kubecfg authors
     2  //
     3  //
     4  //    Licensed under the Apache License, Version 2.0 (the "License");
     5  //    you may not use this file except in compliance with the License.
     6  //    You may obtain a copy of the License at
     7  //
     8  //      http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  //    Unless required by applicable law or agreed to in writing, software
    11  //    distributed under the License is distributed on an "AS IS" BASIS,
    12  //    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  //    See the License for the specific language governing permissions and
    14  //    limitations under the License.
    15  
    16  package natives
    17  
    18  // copied from original code at https://github.com/ksonnet/kubecfg/blob/master/utils/nativefuncs.go
    19  // and modified for use.
    20  
    21  import (
    22  	"bytes"
    23  	"encoding/json"
    24  	"fmt"
    25  	"reflect"
    26  	"regexp"
    27  
    28  	"github.com/google/go-jsonnet"
    29  	"github.com/google/go-jsonnet/ast"
    30  	"github.com/pkg/errors"
    31  	"k8s.io/apimachinery/pkg/labels"
    32  )
    33  
    34  // Register adds qbec's native jsonnet functions to the provided VM
    35  func Register(vm *jsonnet.VM) {
    36  	// NB: libjsonnet native functions can only pass primitive
    37  	// types, so some functions json-encode the arg.  These
    38  	// "*FromJson" functions will be replaced by regular native
    39  	// version when libjsonnet is able to support this.
    40  
    41  	vm.NativeFunction(&jsonnet.NativeFunction{
    42  		Name:   "parseJson",
    43  		Params: []ast.Identifier{"json"},
    44  		Func: func(args []interface{}) (res interface{}, err error) {
    45  			str := args[0].(string)
    46  			data := []byte(str)
    47  			res, err = ParseJSON(bytes.NewReader(data))
    48  			return
    49  		},
    50  	})
    51  
    52  	vm.NativeFunction(&jsonnet.NativeFunction{
    53  		Name:   "parseYaml",
    54  		Params: []ast.Identifier{"yaml"},
    55  		Func: func(args []interface{}) (res interface{}, err error) {
    56  			data := []byte(args[0].(string))
    57  			return ParseYAMLDocuments(bytes.NewReader(data))
    58  		},
    59  	})
    60  
    61  	vm.NativeFunction(&jsonnet.NativeFunction{
    62  		Name:   "renderYaml",
    63  		Params: []ast.Identifier{"data"},
    64  		Func: func(args []interface{}) (res interface{}, err error) {
    65  			var buf bytes.Buffer
    66  			err = RenderYAMLDocuments(args[0], &buf)
    67  			if err != nil {
    68  				return nil, err
    69  			}
    70  			return buf.String(), nil
    71  		},
    72  	})
    73  
    74  	vm.NativeFunction(&jsonnet.NativeFunction{
    75  		Name:   "escapeStringRegex",
    76  		Params: []ast.Identifier{"str"},
    77  		Func: func(args []interface{}) (res interface{}, err error) {
    78  			return regexp.QuoteMeta(args[0].(string)), nil
    79  		},
    80  	})
    81  
    82  	vm.NativeFunction(&jsonnet.NativeFunction{
    83  		Name:   "regexMatch",
    84  		Params: []ast.Identifier{"regex", "string"},
    85  		Func: func(args []interface{}) (res interface{}, err error) {
    86  			return regexp.MatchString(args[0].(string), args[1].(string))
    87  		},
    88  	})
    89  
    90  	vm.NativeFunction(&jsonnet.NativeFunction{
    91  		Name:   "regexSubst",
    92  		Params: []ast.Identifier{"regex", "src", "repl"},
    93  		Func: func(args []interface{}) (res interface{}, err error) {
    94  			regex := args[0].(string)
    95  			src := args[1].(string)
    96  			repl := args[2].(string)
    97  
    98  			r, err := regexp.Compile(regex)
    99  			if err != nil {
   100  				return "", err
   101  			}
   102  			return r.ReplaceAllString(src, repl), nil
   103  		},
   104  	})
   105  
   106  	vm.NativeFunction(&jsonnet.NativeFunction{
   107  		Name:   "expandHelmTemplate",
   108  		Params: []ast.Identifier{"chart", "values", "options"},
   109  		Func: func(args []interface{}) (res interface{}, err error) {
   110  			chart := args[0].(string)
   111  			values := args[1].(map[string]interface{})
   112  			options := args[2].(map[string]interface{})
   113  			var h helmOptions
   114  			b, err := json.Marshal(options)
   115  			if err != nil {
   116  				return nil, errors.Wrap(err, "marshal options to JSON")
   117  			}
   118  			if err := json.Unmarshal(b, &h); err != nil {
   119  				return nil, errors.Wrap(err, "unmarshal options from JSON")
   120  			}
   121  			return expandHelmTemplate(chart, values, h)
   122  		},
   123  	})
   124  
   125  	vm.NativeFunction(&jsonnet.NativeFunction{
   126  		Name:   "labelsMatchSelector",
   127  		Params: []ast.Identifier{"labels", "selectorString"},
   128  		Func: func(args []interface{}) (res interface{}, err error) {
   129  			lbls, ok := args[0].(map[string]interface{})
   130  			if !ok {
   131  				return nil, fmt.Errorf("invalid labels type, %v, want a map", reflect.TypeOf(args[0]))
   132  			}
   133  			selStr, ok := args[1].(string)
   134  			if !ok {
   135  				return nil, fmt.Errorf("invalid selector of type %v, want a string", reflect.TypeOf(args[1]))
   136  			}
   137  			input := map[string]string{}
   138  			for k, v := range lbls {
   139  				val, ok := v.(string)
   140  				if !ok {
   141  					return nil, fmt.Errorf("invalid label map value, %v, want a string", reflect.TypeOf(v))
   142  				}
   143  				input[k] = val
   144  			}
   145  			sel, err := labels.Parse(selStr)
   146  			if err != nil {
   147  				return false, fmt.Errorf("invalid label selector: '%s', %v", selStr, err)
   148  			}
   149  			return sel.Matches(labels.Set(input)), nil
   150  		},
   151  	})
   152  }