-
Notifications
You must be signed in to change notification settings - Fork 11
/
policy_types.go
215 lines (181 loc) · 6.83 KB
/
policy_types.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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
/*
* Copyright (C) 2022 Appvia Ltd <info@appvia.io>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package v1alpha1
import (
"bytes"
"regexp"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/client"
corev1alpha1 "github.com/appvia/terranetes-controller/pkg/apis/core/v1alpha1"
)
// PolicyKind is the kind for a Policy
const PolicyKind = "Policy"
// PolicyGVK is the GVK for a Policy
var PolicyGVK = schema.GroupVersionKind{
Group: GroupVersion.Group,
Version: GroupVersion.Version,
Kind: PolicyKind,
}
const (
// DefaultVariablesAnnotation is the annotation applied when default variables are set
DefaultVariablesAnnotation = "terraform.appvia.io/defaults"
// SkipDefaultsValidationCheck is the annotation indicating to skip the check
SkipDefaultsValidationCheck = "terraform.appvia.io/skip-defaults-check"
)
// DefaultVariablesSelector is used to determine which configurations the variables
// should be injected into - this can take into account the namespace labels and the
// modules themselvesA
type DefaultVariablesSelector struct {
// Namespace selectors all configurations under one or more namespaces, determined by the
// labeling on the namespace.
// +kubebuilder:validation:Optional
Namespace *metav1.LabelSelector `json:"namespace,omitempty"`
// Modules provides a collection of regexes which are used to match against the
// configuration module
// +kubebuilder:validation:Optional
Modules []string `json:"modules,omitempty"`
}
// IsLabelsMatch returns if the selector matches the namespace label selector
func (d DefaultVariablesSelector) IsLabelsMatch(object client.Object) (bool, error) {
m, err := metav1.LabelSelectorAsSelector(d.Namespace)
if err != nil {
return false, err
}
return m.Matches(labels.Set(object.GetLabels())), nil
}
// IsModulesMatch returns true of the module matches the regex
func (d DefaultVariablesSelector) IsModulesMatch(config *Configuration) (bool, error) {
if len(d.Modules) == 0 {
return false, nil
}
for _, x := range d.Modules {
re, err := regexp.Compile(x)
if err != nil {
return false, err
}
if re.MatchString(config.Spec.Module) {
return true, nil
}
}
return false, nil
}
// DefaultVariables provides platform administrators the ability to inject
// default variables into a configuration
type DefaultVariables struct {
// Selector is used to determine which configurations the variables should be injected into
// +kubebuilder:validation:Required
Selector DefaultVariablesSelector `json:"selector"`
// Secrets is a collection of secrets which are used to inject variables into the configuration
// +kubebuilder:validation:Optional
Secrets []string `json:"secrets,omitempty"`
// Variables is a collection of variables to inject into the configuration
// +kubebuilder:validation:Optional
// +kubebuilder:pruning:PreserveUnknownFields
Variables runtime.RawExtension `json:"variables,omitempty"`
}
// HasVariables returns true if the policy has variables
func (d *DefaultVariables) HasVariables() bool {
switch {
case len(d.Variables.Raw) == 0:
return false
case bytes.Equal(d.Variables.Raw, []byte("{}")):
return false
case bytes.Equal(d.Variables.Raw, []byte("")):
return false
}
return true
}
// HasSelectors returns true if the policy has selectors
func (d *DefaultVariables) HasSelectors() bool {
return d.Selector.Namespace != nil || len(d.Selector.Modules) > 0
}
// PolicySpec defines the desired state of a provider
// +k8s:openapi-gen=true
type PolicySpec struct {
// Summary is an optional field which can be used to define a summary of what the policy is
// configured to enforce.
// +kubebuilder:validation:Optional
Summary string `json:"summary,omitempty"`
// Constraints provides a series or constraints that must be enforced on the selectored
// terraform configurations.
// +kubebuilder:validation:Optional
Constraints *Constraints `json:"constraints,omitempty"`
// Defaults provides the ability to target specific terraform module based on namespace or
// resource labels and automatically inject variables into the configurations.
// +kubebuilder:validation:Optional
Defaults []DefaultVariables `json:"defaults,omitempty"`
}
// +kubebuilder:webhook:name=policies.terraform.appvia.io,mutating=false,path=/validate/terraform.appvia.io/policies,verbs=create;delete;update,groups="terraform.appvia.io",resources=policies,versions=v1alpha1,failurePolicy=fail,sideEffects=None,admissionReviewVersions=v1
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// Policy is the schema for provider definitions in terraform controller
// +k8s:openapi-gen=true
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:resource:path=policies,scope=Cluster,categories={terraform}
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
type Policy struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec PolicySpec `json:"spec,omitempty"`
Status PolicyStatus `json:"status,omitempty"`
}
// PolicyStatus defines the observed state of a provider
// +k8s:openapi-gen=true
type PolicyStatus struct {
corev1alpha1.CommonStatus `json:",inline"`
}
// GetCommonStatus returns the common status
func (p *Policy) GetCommonStatus() *corev1alpha1.CommonStatus {
return &p.Status.CommonStatus
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// PolicyList contains a list of providers
type PolicyList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []Policy `json:"items"`
}
// HasItem returns true if the list contains the item name
func (c *PolicyList) HasItem(name string) bool {
for _, item := range c.Items {
if item.Name == name {
return true
}
}
return false
}
// Merge is called to merge any items which don't exist in the list
func (c *PolicyList) Merge(items []Policy) {
if c.Items == nil {
c.Items = items
return
}
var adding []Policy
for i := 0; i < len(items); i++ {
if c.HasItem(items[i].Name) {
continue
}
adding = append(adding, items[i])
}
if len(adding) > 0 {
c.Items = append(c.Items, adding...)
}
}