-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathtarget.go
131 lines (109 loc) · 3.93 KB
/
target.go
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
126
127
128
129
130
131
package skipper
import (
"fmt"
"path/filepath"
"regexp"
"strings"
)
const (
targetKey string = "target"
useKey string = "use"
)
var wildcardUseRegex regexp.Regexp = *regexp.MustCompile(`^\w+\.\*$`)
// Target defines which classes to use for the compilation.
type Target struct {
File *YamlFile
// Name is the relative path of the file inside the inventory
// where '/' is replaced with '.' and without file extension.
Name string
// UsedWildcardClasses holds all resolved wildcard class imports as specified in the `targets.skipper.use` key.
UsedWildcardClasses []string
// Configuration is the skipper-internal configuration which needs to be present on every target.
Configuration TargetConfig
// SkipperConfig is the generic Skipper configuration which can be use throughout targets and classes
SkipperConfig *SkipperConfig
}
type TargetConfig struct {
Secrets TargetSecretConfig `mapstructure:"secrets,omitempty"`
}
type TargetSecretConfig struct {
Drivers map[string]interface{} `mapstructure:"drivers"`
}
func NewTarget(file *YamlFile, inventoryPath string) (*Target, error) {
if file == nil {
return nil, fmt.Errorf("file cannot be nil")
}
if inventoryPath == "" {
return nil, fmt.Errorf("inventoryPath cannot be empty")
}
// create target name from inventory-relative path
fileName := strings.TrimSuffix(inventoryPath, filepath.Ext(inventoryPath))
name := strings.ReplaceAll(fileName, "/", ".")
// every target must have the same root key
if !file.Data.HasKey(targetKey) {
return nil, fmt.Errorf("target must have valid top-level key")
}
// every target must have the 'skipper' key, which is used to load the Skipper-internal target configuration
var config TargetConfig
err := file.UnmarshalPath(&config, targetKey, skipperKey)
if err != nil {
return nil, fmt.Errorf("missing skipper key in target: %w", err)
}
// attempt to load the generic skipper config
skipperConfig, err := LoadSkipperConfig(file, targetKey)
if err != nil {
return nil, err
}
target := &Target{
File: file,
Name: name,
Configuration: config,
SkipperConfig: skipperConfig,
}
err = target.loadUsedWildcardClasses()
if err != nil {
return nil, err
}
// TODO: do we allow to set the 'target.name' key or is it automatically populated with the target name?
// Or do we handle it the same as kapitan where the value must match the filename?
return target, nil
}
func (t *Target) ReloadConfiguration() {
// every target must have the 'skipper' key, which is used to load the Skipper-internal target configuration
var config TargetConfig
t.File.UnmarshalPath(&config, targetKey, skipperKey)
t.Configuration = config
}
func (t *Target) Data() Data {
return t.File.Data.Get(targetKey)
}
// loadUsedWildcardClasses will extract all wildcards-uses from the configuration,
// remove them from the loaded configuration and store them in UsedWildcardClasses for
// further processing.
func (t *Target) loadUsedWildcardClasses() error {
// convert []interface to []string
for key, class := range t.SkipperConfig.Classes {
// load wildcard imports separately as they need to be resolved
if match := wildcardUseRegex.FindAllString(class, 1); len(match) == 1 {
wildcardUse := match[0]
t.UsedWildcardClasses = append(t.UsedWildcardClasses, wildcardUse)
// remove wildcard classes from regular classes config
t.SkipperConfig.Classes = append(t.SkipperConfig.Classes[:key], t.SkipperConfig.Classes[key+1:]...)
continue
}
}
return nil
}
// targetYamlFileLoader returns a YamlFileLoaderFunc which is capable of
// creating Targets from a given YamlFile.
// The created targets are then appended to the passed targetList.
func targetYamlFileLoader(targetList *[]*Target) YamlFileLoaderFunc {
return func(file *YamlFile, relativePath string) error {
target, err := NewTarget(file, relativePath)
if err != nil {
return fmt.Errorf("%s: %w", file.Path, err)
}
(*targetList) = append((*targetList), target)
return nil
}
}