Skip to content

Commit 89734a6

Browse files
authored
[Backport v0.31.x] Conditonal volumes, service and sidecar. (#463) (#476)
* [Backport v0.31.x] Conditonal volumes, service and sidecar. (#463) * fix changelog * fix changelog
1 parent 3b5033d commit 89734a6

File tree

22 files changed

+809
-119
lines changed

22 files changed

+809
-119
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ install-go-tools: mod-download
2020
go install github.com/pseudomuto/protoc-gen-doc/cmd/protoc-gen-doc
2121
go install github.com/solo-io/[email protected]
2222
go install github.com/golang/mock/[email protected]
23-
go install github.com/onsi/ginkgo/v2/ginkgo@v2.8.1
23+
go install github.com/onsi/ginkgo/v2/ginkgo@v2.9.5
2424
go install golang.org/x/tools/cmd/goimports
2525

2626
# proto compiler installation
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
changelog:
2+
- type: NEW_FEATURE
3+
issueLink: https://github.com/solo-io/gloo-mesh-enterprise/issues/9850
4+
resolvesIssue: false
5+
description: >
6+
Allows specifying conditional volume, service or sidecars.

codegen/cmd_test.go

Lines changed: 113 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package codegen_test
33
import (
44
"bytes"
55
"encoding/json"
6+
"fmt"
67
"io/ioutil"
78
"os"
89
"os/exec"
@@ -39,7 +40,117 @@ var _ = Describe("Cmd", func() {
3940
skv2Imports.External["github.com/solo-io/cue"] = []string{
4041
"encoding/protobuf/cue/cue.proto",
4142
}
43+
It("install conditional sidecars", func() {
44+
var (
45+
agentConditional = "and ($.Values.glooAgent.enabled) ($.Values.glooAgent.runAsSidecar)"
46+
)
47+
48+
cmd := &Command{
49+
Chart: &Chart{
50+
Operators: []Operator{
51+
{
52+
Name: "gloo-mgmt-server",
53+
Service: Service{
54+
Ports: []ServicePort{{
55+
Name: "grpc",
56+
DefaultPort: 9900,
57+
}},
58+
},
59+
Rbac: []rbacv1.PolicyRule{{
60+
Verbs: []string{"*"},
61+
APIGroups: []string{"coordination.k8s.io"},
62+
Resources: []string{"leases"},
63+
}},
64+
Deployment: Deployment{
65+
Sidecars: []Sidecar{
66+
{
67+
Name: "gloo-agent",
68+
Volumes: []v1.Volume{
69+
{
70+
Name: "agent-volume",
71+
VolumeSource: v1.VolumeSource{
72+
Secret: &v1.SecretVolumeSource{
73+
SecretName: "agent-volume",
74+
},
75+
},
76+
},
77+
{
78+
Name: "agent-volume-2",
79+
VolumeSource: v1.VolumeSource{
80+
Secret: &v1.SecretVolumeSource{
81+
SecretName: "agent-volume",
82+
},
83+
},
84+
},
85+
},
86+
Rbac: []rbacv1.PolicyRule{{
87+
Verbs: []string{"*"},
88+
APIGroups: []string{"apiextensions.k8s.io"},
89+
Resources: []string{"customresourcedefinitions"},
90+
}},
91+
Container: Container{
92+
Image: Image{
93+
Registry: "gcr.io/gloo-mesh",
94+
Repository: "gloo-mesh-agent",
95+
Tag: "0.0.1",
96+
},
97+
},
98+
Service: Service{
99+
Ports: []ServicePort{{
100+
Name: "grpc",
101+
DefaultPort: 9977,
102+
}},
103+
},
104+
EnableStatement: agentConditional,
105+
ValuesPath: "$.Values.glooAgent",
106+
},
107+
},
108+
Container: Container{
109+
Image: Image{
110+
Registry: "gcr.io/gloo-mesh",
111+
Repository: "gloo-mesh-mgmt-server",
112+
Tag: "0.0.1",
113+
},
114+
VolumeMounts: []v1.VolumeMount{{
115+
Name: "license-keys",
116+
MountPath: "/etc/gloo-mesh/license-keys",
117+
ReadOnly: true,
118+
}},
119+
},
120+
Volumes: []v1.Volume{
121+
{
122+
Name: "license-keys",
123+
VolumeSource: v1.VolumeSource{
124+
Secret: &v1.SecretVolumeSource{
125+
SecretName: "license-keys",
126+
},
127+
},
128+
},
129+
},
130+
},
131+
},
132+
{
133+
Name: "gloo-agent",
134+
CustomEnableCondition: `and ($.Values.glooAgent.enabled) (not $.Values.glooAgent.runAsSidecar)`,
135+
},
136+
},
137+
},
138+
ManifestRoot: "codegen/test/chart/conditional-sidecar",
139+
}
140+
141+
Expect(cmd.Execute()).NotTo(HaveOccurred(), "failed to execute command")
42142

143+
absPath, err := filepath.Abs("./test/chart/conditional-sidecar/templates/deployment.yaml")
144+
Expect(err).NotTo(HaveOccurred(), "failed to get abs path")
145+
146+
deployment, err := os.ReadFile(absPath)
147+
Expect(err).NotTo(HaveOccurred(), "failed to read deployment.yaml")
148+
149+
Expect(deployment).To(ContainSubstring(fmt.Sprintf("{{- if %s -}}", agentConditional)))
150+
Expect(deployment).To(ContainSubstring(fmt.Sprintf("{{- if %s }}", "and ($.Values.glooAgent.enabled) (not $.Values.glooAgent.runAsSidecar)")))
151+
Expect(deployment).To(ContainSubstring("name: agent-volume"))
152+
Expect(deployment).To(ContainSubstring("{{ $glooAgent.ports.grpc }}"))
153+
})
43154
It("generates controller code and manifests for a proto file", func() {
44155
cmd := &Command{
45156
Groups: []Group{
@@ -1107,8 +1218,8 @@ var _ = Describe("Cmd", func() {
11071218
Chart: &Chart{
11081219
Operators: []Operator{
11091220
{
1110-
Name: "painter",
1111-
EnabledDependsOn: []string{"test1", "test2"},
1221+
Name: "painter",
1222+
CustomEnableCondition: "and $painter.enabled $.Values.test1.enabled $.Values.test2.enabled",
11121223
Rbac: []rbacv1.PolicyRule{
11131224
{
11141225
Verbs: []string{"GET"},

codegen/model/chart.go

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99

1010
"github.com/iancoleman/strcase"
1111
"github.com/solo-io/skv2/codegen/doc"
12-
v1 "k8s.io/api/core/v1"
12+
corev1 "k8s.io/api/core/v1"
1313
rbacv1 "k8s.io/api/rbac/v1"
1414
)
1515

@@ -84,14 +84,15 @@ type Operator struct {
8484
// Custom values to include at operator level
8585
Values interface{}
8686

87-
// (Optional) If this operator depends on another operator being enabled,
88-
// the name of the other operator can be included in this list. This operator
89-
// will not be provisioned unless both are enabled (by having values.enabled = true)
90-
EnabledDependsOn []string
91-
9287
// (Optional) If this operator should be applied to a namespace
9388
// specified in a common value (e.g. "$Values.common.addonNamespace") specify the full value path here
9489
NamespaceFromValuePath string
90+
91+
// Optional: if specified, the operator resources will be abled based on the
92+
// condition specified in the enable statement.
93+
//
94+
// E.g: `and (.Values.operator.customValueA) (.Values.operator.customValueB)`
95+
CustomEnableCondition string
9596
}
9697

9798
func (o Operator) FormattedName() string {
@@ -108,7 +109,7 @@ type Deployment struct {
108109
UseDaemonSet bool
109110
Container
110111
Sidecars []Sidecar
111-
Volumes []v1.Volume
112+
Volumes []corev1.Volume
112113
CustomPodLabels map[string]string
113114
CustomPodAnnotations map[string]string
114115
CustomDeploymentLabels map[string]string
@@ -119,25 +120,30 @@ type Deployment struct {
119120
type Container struct {
120121
// not configurable via helm values
121122
Args []string
122-
VolumeMounts []v1.VolumeMount
123-
ReadinessProbe *v1.Probe
124-
LivenessProbe *v1.Probe
123+
VolumeMounts []corev1.VolumeMount
124+
ReadinessProbe *corev1.Probe
125+
LivenessProbe *corev1.Probe
125126

126127
Image Image
127-
Env []v1.EnvVar
128-
Resources *v1.ResourceRequirements
129-
SecurityContext *v1.SecurityContext
128+
Env []corev1.EnvVar
129+
Resources *corev1.ResourceRequirements
130+
SecurityContext *corev1.SecurityContext
130131
}
131132

132133
// sidecars require a container config and a unique name
133134
type Sidecar struct {
134135
Container
135-
Name string
136+
Service
137+
Rbac []rbacv1.PolicyRule
138+
Volumes []corev1.Volume
139+
Name string
140+
EnableStatement string `json:"enableStatement,omitempty" yaml:"enableStatement,omitempty"` // Optional: if specified, the operator resources will be abled based on the condition specified in the enable statement.
141+
ValuesPath string `json:"valuesPath,omitempty" yaml:"valuesPath,omitempty"` // Override for values path in generated yaml.
136142
}
137143

138144
// values for struct template
139145
type Service struct {
140-
Type v1.ServiceType
146+
Type corev1.ServiceType
141147
Ports []ServicePort
142148
CustomLabels map[string]string
143149
CustomAnnotations map[string]string
@@ -192,6 +198,11 @@ func (c Chart) BuildChartValues() values.UserHelmValues {
192198
}
193199
sidecars := map[string]values.UserContainerValues{}
194200
for _, sidecar := range operator.Deployment.Sidecars {
201+
// Note: We don't want to render docs for conditional sidecars
202+
if sidecar.ValuesPath != "" {
203+
continue
204+
}
205+
195206
sidecars[strcase.ToLowerCamel(sidecar.Name)] = makeContainerDocs(sidecar.Container)
196207
}
197208

codegen/render/funcs.go

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ import (
1414
"github.com/solo-io/skv2/codegen/model/values"
1515
"github.com/solo-io/skv2/codegen/util/stringutils"
1616
"google.golang.org/protobuf/types/known/structpb"
17-
v1 "k8s.io/api/core/v1"
17+
corev1 "k8s.io/api/core/v1"
18+
rbacv1 "k8s.io/api/rbac/v1"
19+
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
1820
"k8s.io/apimachinery/pkg/api/resource"
1921
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2022
"k8s.io/apimachinery/pkg/util/intstr"
@@ -129,8 +131,16 @@ func makeTemplateFuncs(customFuncs template.FuncMap) template.FuncMap {
129131
},
130132

131133
"containerConfigs": containerConfigs,
134+
"toListItem": toListItem,
135+
"opVar": opVar,
132136

133-
"opVar": opVar,
137+
"render_outer_conditional_crd_template": func(crd apiextv1.CustomResourceDefinition, currentVersion string, skips map[string]bool) bool {
138+
return len(crd.Spec.Versions) < 2 && strings.Contains(currentVersion, "alpha") && !skips[crd.Spec.Group+"/"+currentVersion]
139+
},
140+
141+
"render_inner_conditional_crd_template": func(crd apiextv1.CustomResourceDefinition, currentVersion string, skips map[string]bool) bool {
142+
return len(crd.Spec.Versions) > 1 && strings.Contains(currentVersion, "alpha") && !skips[crd.Spec.Group+"/"+currentVersion]
143+
},
134144
}
135145

136146
for k, v := range skv2Funcs {
@@ -144,10 +154,18 @@ func makeTemplateFuncs(customFuncs template.FuncMap) template.FuncMap {
144154
return f
145155
}
146156

157+
func toListItem(item interface{}) []interface{} {
158+
return []interface{}{item}
159+
}
160+
147161
type containerConfig struct {
148162
model.Container
149-
Name string
150-
ValuesVar string
163+
model.Service
164+
Rbac []rbacv1.PolicyRule
165+
Volumes []corev1.Volume
166+
Name string
167+
ValuesVar string
168+
EnableStatement string
151169
}
152170

153171
func containerConfigs(op model.Operator) []containerConfig {
@@ -159,11 +177,21 @@ func containerConfigs(op model.Operator) []containerConfig {
159177
}}
160178

161179
for _, sidecar := range op.Deployment.Sidecars {
162-
configs = append(configs, containerConfig{
163-
Container: sidecar.Container,
164-
Name: sidecar.Name,
165-
ValuesVar: valuesVar + ".sidecars." + strcase.ToLowerCamel(sidecar.Name),
166-
})
180+
config := containerConfig{
181+
EnableStatement: sidecar.EnableStatement, // Change this to base name of operator e.g: $.Values.glooAgent.X
182+
Rbac: sidecar.Rbac,
183+
Volumes: sidecar.Volumes,
184+
Service: sidecar.Service,
185+
Container: sidecar.Container,
186+
Name: sidecar.Name,
187+
ValuesVar: valuesVar + ".sidecars." + strcase.ToLowerCamel(sidecar.Name),
188+
}
189+
190+
if sidecar.ValuesPath != "" {
191+
config.ValuesVar = sidecar.ValuesPath
192+
}
193+
194+
configs = append(configs, config)
167195
}
168196

169197
return configs
@@ -719,7 +747,7 @@ func createCustomTypeMapper(values values.UserHelmValues) customTypeMapper {
719747
}
720748
},
721749

722-
reflect.TypeOf(v1.SecurityContext{}): func(t reflect.Type, defaultSchema *jsonschema.Schema) *jsonschema.Schema {
750+
reflect.TypeOf(corev1.SecurityContext{}): func(t reflect.Type, defaultSchema *jsonschema.Schema) *jsonschema.Schema {
723751
return &jsonschema.Schema{
724752
AnyOf: []*jsonschema.Schema{
725753
defaultSchema,

0 commit comments

Comments
 (0)