github.com/Ilhicas/nomad@v1.0.4-0.20210304152020-e86851182bc3/jobspec/parse_multiregion.go (about)

     1  package jobspec
     2  
     3  import (
     4  	"fmt"
     5  
     6  	multierror "github.com/hashicorp/go-multierror"
     7  	"github.com/hashicorp/hcl"
     8  	"github.com/hashicorp/hcl/hcl/ast"
     9  	"github.com/hashicorp/nomad/api"
    10  	"github.com/mitchellh/mapstructure"
    11  )
    12  
    13  func parseMultiregion(result *api.Multiregion, list *ast.ObjectList) error {
    14  
    15  	list = list.Elem()
    16  	if len(list.Items) > 1 {
    17  		return fmt.Errorf("only one 'multiregion' block allowed")
    18  	}
    19  	if len(list.Items) == 0 {
    20  		return nil
    21  	}
    22  
    23  	// Get our multiregion object and decode it
    24  	obj := list.Items[0]
    25  	var m map[string]interface{}
    26  	if err := hcl.DecodeObject(&m, obj.Val); err != nil {
    27  		return err
    28  	}
    29  
    30  	// Value should be an object
    31  	var listVal *ast.ObjectList
    32  	if ot, ok := obj.Val.(*ast.ObjectType); ok {
    33  		listVal = ot.List
    34  	} else {
    35  		return fmt.Errorf("multiregion should be an object")
    36  	}
    37  
    38  	// Check for invalid keys
    39  	valid := []string{
    40  		"strategy",
    41  		"region",
    42  	}
    43  	if err := checkHCLKeys(obj.Val, valid); err != nil {
    44  		return err
    45  	}
    46  
    47  	// If we have a strategy, then parse that
    48  	if o := listVal.Filter("strategy"); len(o.Items) > 0 {
    49  		if err := parseMultiregionStrategy(&result.Strategy, o); err != nil {
    50  			return multierror.Prefix(err, "strategy ->")
    51  		}
    52  	}
    53  	// If we have regions, then parse those
    54  	if o := listVal.Filter("region"); len(o.Items) > 0 {
    55  		if err := parseMultiregionRegions(result, o); err != nil {
    56  			return multierror.Prefix(err, "regions ->")
    57  		}
    58  	} else {
    59  		return fmt.Errorf("'multiregion' requires one or more 'region' blocks")
    60  	}
    61  	return nil
    62  }
    63  
    64  func parseMultiregionStrategy(final **api.MultiregionStrategy, list *ast.ObjectList) error {
    65  	list = list.Elem()
    66  	if len(list.Items) > 1 {
    67  		return fmt.Errorf("only one 'strategy' block allowed")
    68  	}
    69  
    70  	// Get our job object
    71  	obj := list.Items[0]
    72  
    73  	// Check for invalid keys
    74  	valid := []string{
    75  		"max_parallel",
    76  		"on_failure",
    77  	}
    78  	if err := checkHCLKeys(obj.Val, valid); err != nil {
    79  		return err
    80  	}
    81  
    82  	var m map[string]interface{}
    83  	if err := hcl.DecodeObject(&m, obj.Val); err != nil {
    84  		return err
    85  	}
    86  
    87  	var result api.MultiregionStrategy
    88  	dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
    89  		WeaklyTypedInput: true,
    90  		Result:           &result,
    91  	})
    92  
    93  	if err != nil {
    94  		return err
    95  	}
    96  	if err := dec.Decode(m); err != nil {
    97  		return err
    98  	}
    99  	*final = &result
   100  	return nil
   101  }
   102  
   103  func parseMultiregionRegions(result *api.Multiregion, list *ast.ObjectList) error {
   104  	list = list.Children()
   105  	if len(list.Items) == 0 {
   106  		return nil
   107  	}
   108  
   109  	// Go through each object and turn it into an actual result.
   110  	collection := make([]*api.MultiregionRegion, 0, len(list.Items))
   111  	seen := make(map[string]struct{})
   112  	for _, item := range list.Items {
   113  		n := item.Keys[0].Token.Value().(string)
   114  
   115  		// Make sure we haven't already found this
   116  		if _, ok := seen[n]; ok {
   117  			return fmt.Errorf("region '%s' defined more than once", n)
   118  		}
   119  		seen[n] = struct{}{}
   120  
   121  		// We need this later
   122  		var listVal *ast.ObjectList
   123  		if ot, ok := item.Val.(*ast.ObjectType); ok {
   124  			listVal = ot.List
   125  		} else {
   126  			return fmt.Errorf("region '%s': should be an object", n)
   127  		}
   128  
   129  		// Check for invalid keys
   130  		valid := []string{
   131  			"count",
   132  			"datacenters",
   133  			"meta",
   134  		}
   135  		if err := checkHCLKeys(listVal, valid); err != nil {
   136  			return multierror.Prefix(err, fmt.Sprintf("'%s' ->", n))
   137  		}
   138  
   139  		var m map[string]interface{}
   140  		if err := hcl.DecodeObject(&m, item.Val); err != nil {
   141  			return err
   142  		}
   143  
   144  		// Build the region with the basic decode
   145  		var r api.MultiregionRegion
   146  		r.Name = n
   147  		dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
   148  			WeaklyTypedInput: true,
   149  			Result:           &r,
   150  		})
   151  		if err != nil {
   152  			return err
   153  		}
   154  		if err := dec.Decode(m); err != nil {
   155  			return err
   156  		}
   157  		collection = append(collection, &r)
   158  	}
   159  
   160  	result.Regions = append(result.Regions, collection...)
   161  	return nil
   162  }