summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/hashicorp/go-sockaddr/template/template.go
blob: ffe467b7f55f07a39733c9029a662253dc81bbe8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package template

import (
	"bytes"
	"fmt"
	"text/template"

	"github.com/hashicorp/errwrap"
	sockaddr "github.com/hashicorp/go-sockaddr"
)

var (
	// SourceFuncs is a map of all top-level functions that generate
	// sockaddr data types.
	SourceFuncs template.FuncMap

	// SortFuncs is a map of all functions used in sorting
	SortFuncs template.FuncMap

	// FilterFuncs is a map of all functions used in sorting
	FilterFuncs template.FuncMap

	// HelperFuncs is a map of all functions used in sorting
	HelperFuncs template.FuncMap
)

func init() {
	SourceFuncs = template.FuncMap{
		// GetAllInterfaces - Returns an exhaustive set of IfAddr
		// structs available on the host.  `GetAllInterfaces` is the
		// initial input and accessible as the initial "dot" in the
		// pipeline.
		"GetAllInterfaces": sockaddr.GetAllInterfaces,

		// GetDefaultInterfaces - Returns one IfAddr for every IP that
		// is on the interface containing the default route for the
		// host.
		"GetDefaultInterfaces": sockaddr.GetDefaultInterfaces,

		// GetPrivateInterfaces - Returns one IfAddr for every IP that
		// matches RFC 6890, are attached to the interface with the
		// default route, and are forwardable IP addresses.  NOTE: RFC
		// 6890 is a more exhaustive version of RFC1918 because it spans
		// IPv4 and IPv6, however it doespermit the inclusion of likely
		// undesired addresses such as multicast, therefore our
		// definition of a "private" address also excludes
		// non-forwardable IP addresses (as defined by the IETF).
		"GetPrivateInterfaces": sockaddr.GetPrivateInterfaces,

		// GetPublicInterfaces - Returns a list of IfAddr that do not
		// match RFC 6890, are attached to the default route, and are
		// forwardable.
		"GetPublicInterfaces": sockaddr.GetPublicInterfaces,
	}

	SortFuncs = template.FuncMap{
		"sort": sockaddr.SortIfBy,
	}

	FilterFuncs = template.FuncMap{
		"exclude": sockaddr.ExcludeIfs,
		"include": sockaddr.IncludeIfs,
	}

	HelperFuncs = template.FuncMap{
		// Misc functions that operate on IfAddrs inputs
		"attr":   sockaddr.IfAttr,
		"join":   sockaddr.JoinIfAddrs,
		"limit":  sockaddr.LimitIfAddrs,
		"offset": sockaddr.OffsetIfAddrs,
		"unique": sockaddr.UniqueIfAddrsBy,

		// Return a Private RFC 6890 IP address string that is attached
		// to the default route and a forwardable address.
		"GetPrivateIP": sockaddr.GetPrivateIP,

		// Return a Public RFC 6890 IP address string that is attached
		// to the default route and a forwardable address.
		"GetPublicIP": sockaddr.GetPublicIP,

		// Return the first IP address of the named interface, sorted by
		// the largest network size.
		"GetInterfaceIP": sockaddr.GetInterfaceIP,
	}
}

// Parse parses input as template input using the addresses available on the
// host, then returns the string output if there are no errors.
func Parse(input string) (string, error) {
	addrs, err := sockaddr.GetAllInterfaces()
	if err != nil {
		return "", errwrap.Wrapf("unable to query interface addresses: {{err}}", err)
	}

	return ParseIfAddrs(input, addrs)
}

// ParseIfAddrs parses input as template input using the IfAddrs inputs, then
// returns the string output if there are no errors.
func ParseIfAddrs(input string, ifAddrs sockaddr.IfAddrs) (string, error) {
	return ParseIfAddrsTemplate(input, ifAddrs, template.New("sockaddr.Parse"))
}

// ParseIfAddrsTemplate parses input as template input using the IfAddrs inputs,
// then returns the string output if there are no errors.
func ParseIfAddrsTemplate(input string, ifAddrs sockaddr.IfAddrs, tmplIn *template.Template) (string, error) {
	// Create a template, add the function map, and parse the text.
	tmpl, err := tmplIn.Option("missingkey=error").
		Funcs(SourceFuncs).
		Funcs(SortFuncs).
		Funcs(FilterFuncs).
		Funcs(HelperFuncs).
		Parse(input)
	if err != nil {
		return "", errwrap.Wrapf(fmt.Sprintf("unable to parse template %+q: {{err}}", input), err)
	}

	var outWriter bytes.Buffer
	err = tmpl.Execute(&outWriter, ifAddrs)
	if err != nil {
		return "", errwrap.Wrapf(fmt.Sprintf("unable to execute sockaddr input %+q: {{err}}", input), err)
	}

	return outWriter.String(), nil
}