Skip to content

Commit f5644e4

Browse files
committed
refactor: improve config validation
1 parent a2a0c62 commit f5644e4

5 files changed

Lines changed: 97 additions & 62 deletions

File tree

cmd/run_pipeline.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ func (cmd *RunPipelineCmd) AddFlags(command *cobra.Command) {
9191
command.Flags().BoolVar(&cmd.SkipPush, "skip-push", cmd.SkipPush, "Skips image pushing, useful for minikube deployment")
9292
command.Flags().BoolVar(&cmd.SkipPushLocalKubernetes, "skip-push-local-kube", cmd.SkipPushLocalKubernetes, "Skips image pushing, if a local kubernetes environment is detected")
9393

94-
command.Flags().BoolVarP(&cmd.Terminal, "terminal", "t", cmd.Terminal, "Open a terminal instead of showing logs")
94+
command.Flags().BoolVar(&cmd.Terminal, "terminal", cmd.Terminal, "Open a terminal instead of showing logs")
9595
command.Flags().BoolVar(&cmd.ShowUI, "show-ui", cmd.ShowUI, "Shows the ui server")
9696
}
9797

pkg/devspace/config/loader/validate.go

Lines changed: 36 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ func Validate(config *latest.Config) error {
4545
return err
4646
}
4747

48+
err = validatePipelines(config)
49+
if err != nil {
50+
return err
51+
}
52+
4853
err = validateImages(config)
4954
if err != nil {
5055
return err
@@ -85,11 +90,8 @@ func Validate(config *latest.Config) error {
8590

8691
func validateVars(vars map[string]*latest.Variable) error {
8792
for i, v := range vars {
88-
if i == "" {
89-
return fmt.Errorf("vars[*].name has to be specified")
90-
}
9193
if encoding.IsUnsafeUpperName(v.Name) {
92-
return fmt.Errorf("vars[%s].name %s has to match the following regex: %v", i, v.Name, encoding.UnsafeUpperNameRegEx.String())
94+
return fmt.Errorf("vars.%s has to match the following regex: %v", i, encoding.UnsafeUpperNameRegEx.String())
9395
}
9496
}
9597

@@ -118,16 +120,26 @@ func validateRequire(config *latest.Config) error {
118120
return nil
119121
}
120122

123+
func validatePipelines(config *latest.Config) error {
124+
for name := range config.Pipelines {
125+
if encoding.IsUnsafeName(name) {
126+
return fmt.Errorf("pipelines.%s has to match the following regex: %v", name, encoding.UnsafeNameRegEx.String())
127+
}
128+
}
129+
130+
return nil
131+
}
132+
121133
func validateDependencies(config *latest.Config) error {
122134
for name, dep := range config.Dependencies {
123135
if encoding.IsUnsafeName(name) {
124-
return fmt.Errorf("dependencies[%s] has to match the following regex: %v", name, encoding.UnsafeNameRegEx.String())
136+
return fmt.Errorf("dependencies.%s has to match the following regex: %v", name, encoding.UnsafeNameRegEx.String())
125137
}
126138
if dep.Source == nil {
127-
return errors.Errorf("dependencies[%s].source is required", name)
139+
return errors.Errorf("dependencies.%s.source is required", name)
128140
}
129141
if dep.Source.Git == "" && dep.Source.Path == "" {
130-
return errors.Errorf("dependencies[%s].git or dependencies[%s].path is required", name, name)
142+
return errors.Errorf("dependencies.%s.git or dependencies[%s].path is required", name, name)
131143
}
132144
}
133145

@@ -136,14 +148,11 @@ func validateDependencies(config *latest.Config) error {
136148

137149
func validateCommands(config *latest.Config) error {
138150
for key, command := range config.Commands {
139-
if command.Name == "" {
140-
return errors.Errorf("commands[%s].name is required", key)
141-
}
142-
if encoding.IsUnsafeUpperName(command.Name) {
143-
return fmt.Errorf("commands[%s] has to match the following regex: %v", command.Name, encoding.UnsafeUpperNameRegEx.String())
151+
if encoding.IsUnsafeName(command.Name) {
152+
return fmt.Errorf("commands.%s has to match the following regex: %v", command.Name, encoding.UnsafeNameRegEx.String())
144153
}
145154
if command.Command == "" {
146-
return errors.Errorf("commands[%s].command is required", key)
155+
return errors.Errorf("commands.%s.command is required", key)
147156
}
148157
}
149158

@@ -207,18 +216,18 @@ func validateHooks(config *latest.Config) error {
207216

208217
func validateDeployments(config *latest.Config) error {
209218
for index, deployConfig := range config.Deployments {
210-
if deployConfig.Name == "" {
211-
return errors.Errorf("deployments[%s].name is required", index)
212-
}
213219
if encoding.IsUnsafeName(deployConfig.Name) {
214-
return fmt.Errorf("deployments[%s].name %s has to match the following regex: %v", index, deployConfig.Name, encoding.UnsafeNameRegEx.String())
220+
return fmt.Errorf("deployments.%s has to match the following regex: %v", index, encoding.UnsafeNameRegEx.String())
215221
}
216222
if deployConfig.Helm == nil && deployConfig.Kubectl == nil {
217223
return errors.Errorf("Please specify either helm or kubectl as deployment type in deployment %s", deployConfig.Name)
218224
}
219225
if deployConfig.Kubectl != nil && deployConfig.Kubectl.Manifests == nil {
220226
return errors.Errorf("deployments[%s].kubectl.manifests is required", index)
221227
}
228+
if deployConfig.Kubectl != nil && deployConfig.Helm != nil {
229+
return errors.Errorf("deployments[%s].kubectl and deployments[%s].helm cannot be used together", index, index)
230+
}
222231
}
223232

224233
return nil
@@ -243,11 +252,11 @@ func ValidateComponentConfig(deployConfig *latest.DeploymentConfig, overwriteVal
243252

244253
func validatePullSecrets(config *latest.Config) error {
245254
for _, ps := range config.PullSecrets {
246-
if ps.Name == "" {
247-
return errors.Errorf("pull secret keys cannot be an empty string")
248-
}
249255
if encoding.IsUnsafeName(ps.Name) {
250-
return fmt.Errorf("pullSecrets[%s] has to match the following regex: %v", ps.Name, encoding.UnsafeNameRegEx.String())
256+
return fmt.Errorf("pullSecrets.%s has to match the following regex: %v", ps.Name, encoding.UnsafeNameRegEx.String())
257+
}
258+
if ps.Registry == "" {
259+
return fmt.Errorf("pullSecrets.%s.registry is required", ps.Name)
251260
}
252261
}
253262

@@ -258,11 +267,8 @@ func validateImages(config *latest.Config) error {
258267
// images lists all the image names in order to check for duplicates
259268
images := map[string]bool{}
260269
for imageConfigName, imageConf := range config.Images {
261-
if imageConfigName == "" {
262-
return errors.Errorf("images keys cannot be an empty string")
263-
}
264270
if encoding.IsUnsafeName(imageConfigName) {
265-
return fmt.Errorf("images[%s] has to match the following regex: %v", imageConfigName, encoding.UnsafeNameRegEx.String())
271+
return fmt.Errorf("images.%s has to match the following regex: %v", imageConfigName, encoding.UnsafeNameRegEx.String())
266272
}
267273
if imageConf == nil {
268274
return errors.Errorf("images.%s is empty and should at least contain an image name", imageConfigName)
@@ -304,14 +310,11 @@ func validateImages(config *latest.Config) error {
304310
func validateDev(config *latest.Config) error {
305311
for devPodName, devPod := range config.Dev {
306312
devPodName = strings.TrimSpace(devPodName)
307-
if devPodName == "" {
308-
return errors.Errorf("dev[%s] is required", devPodName)
309-
}
310313
if encoding.IsUnsafeName(devPodName) {
311-
return fmt.Errorf("dev[%s] has to match the following regex: %v", devPodName, encoding.UnsafeNameRegEx.String())
314+
return fmt.Errorf("dev.%s has to match the following regex: %v", devPodName, encoding.UnsafeNameRegEx.String())
312315
}
313316
if len(devPod.LabelSelector) == 0 && devPod.ImageSelector == "" {
314-
return errors.Errorf("dev[%s]: image selector and label selector are nil", devPodName)
317+
return errors.Errorf("dev.%s: image selector and label selector are nil", devPodName)
315318
}
316319

317320
definedSelectors := 0
@@ -322,16 +325,16 @@ func validateDev(config *latest.Config) error {
322325
definedSelectors++
323326
}
324327
if definedSelectors > 1 {
325-
return errors.Errorf("dev[%s]: image selector and label selector cannot all be defined", devPodName)
328+
return errors.Errorf("dev.%s: image selector and label selector cannot be used together", devPodName)
326329
}
327330

328-
err := validateDevContainer(fmt.Sprintf("dev[%s]", devPodName), &devPod.DevContainer, false)
331+
err := validateDevContainer(fmt.Sprintf("dev.%s", devPodName), &devPod.DevContainer, false)
329332
if err != nil {
330333
return err
331334
}
332335
if len(devPod.Containers) > 0 {
333336
for i, c := range devPod.Containers {
334-
err := validateDevContainer(fmt.Sprintf("dev[%s].containers[%s]", devPodName, i), c, true)
337+
err := validateDevContainer(fmt.Sprintf("dev.%s.containers[%s]", devPodName, i), c, true)
335338
if err != nil {
336339
return err
337340
}

pkg/devspace/config/remotecache/loader.go

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,45 +12,43 @@ import (
1212
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1313
)
1414

15+
const (
16+
SecretType = "devspace.sh/remote-cache"
17+
)
18+
1519
// Loader is the interface for loading the cache
1620
type Loader interface {
1721
Load(ctx context.Context, client kubectl.Client) (Cache, error)
1822
}
1923

2024
// NewCache generates a new generated config
21-
func NewCache(secretName string) *RemoteCache {
25+
func NewCache(configName, secretName string) *RemoteCache {
2226
return &RemoteCache{
2327
Vars: make(map[string]string),
2428
Deployments: []DeploymentCache{},
2529
DevPods: []DevPodCache{},
2630
Data: make(map[string]string),
2731
secretName: secretName,
32+
configName: configName,
2833
}
2934
}
3035

31-
// NewCacheLoader creates a new remote cache loader for the given DevSpace configuration name
32-
func NewCacheLoader(devSpaceName string) Loader {
33-
return &cacheLoader{
34-
secretName: secretName(devSpaceName),
36+
// NewCacheFromSecret loads the cache from secret
37+
func NewCacheFromSecret(ctx context.Context, client kubectl.Client, secretName string) (*RemoteCache, error) {
38+
secret, err := client.KubeClient().CoreV1().Secrets(client.Namespace()).Get(ctx, secretName, metav1.GetOptions{})
39+
if err != nil {
40+
return nil, err
3541
}
36-
}
3742

38-
type cacheLoader struct {
39-
secretName string
40-
}
41-
42-
func (c *cacheLoader) Load(ctx context.Context, client kubectl.Client) (Cache, error) {
43-
secret, err := client.KubeClient().CoreV1().Secrets(client.Namespace()).Get(ctx, c.secretName, metav1.GetOptions{})
44-
if err != nil {
45-
if !kerrors.IsNotFound(err) && !kerrors.IsForbidden(err) {
46-
return nil, err
47-
}
43+
// get config name
44+
configName := ""
45+
if secret.Labels != nil {
46+
configName = secret.Labels["name"]
47+
}
4848

49-
s := NewCache(c.secretName)
50-
s.secretNamespace = client.Namespace()
51-
return s, nil
52-
} else if secret.Data == nil || len(secret.Data["cache"]) == 0 {
53-
s := NewCache(c.secretName)
49+
// return secret
50+
if secret.Data == nil || len(secret.Data["cache"]) == 0 {
51+
s := NewCache(configName, secretName)
5452
s.secretNamespace = client.Namespace()
5553
return s, nil
5654
}
@@ -95,11 +93,40 @@ func (c *cacheLoader) Load(ctx context.Context, client kubectl.Client) (Cache, e
9593
remoteCache.VarsEncrypted = false
9694
}
9795

98-
remoteCache.secretName = c.secretName
96+
remoteCache.configName = configName
97+
remoteCache.secretName = secretName
9998
remoteCache.secretNamespace = client.Namespace()
10099
return remoteCache, nil
101100
}
102101

102+
// NewCacheLoader creates a new remote cache loader for the given DevSpace configuration name
103+
func NewCacheLoader(devSpaceName string) Loader {
104+
return &cacheLoader{
105+
secretName: secretName(devSpaceName),
106+
configName: devSpaceName,
107+
}
108+
}
109+
110+
type cacheLoader struct {
111+
secretName string
112+
configName string
113+
}
114+
115+
func (c *cacheLoader) Load(ctx context.Context, client kubectl.Client) (Cache, error) {
116+
remoteCache, err := NewCacheFromSecret(ctx, client, c.secretName)
117+
if err != nil {
118+
if !kerrors.IsNotFound(err) && !kerrors.IsForbidden(err) {
119+
return nil, err
120+
}
121+
122+
s := NewCache(c.configName, c.secretName)
123+
s.secretNamespace = client.Namespace()
124+
return s, nil
125+
}
126+
127+
return remoteCache, nil
128+
}
129+
103130
func secretName(devSpaceName string) string {
104131
return encoding.SafeConcatName("devspace", "cache", devSpaceName)
105132
}

pkg/devspace/config/remotecache/schema.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,11 @@ type RemoteCache struct {
5454
Data map[string]string `yaml:"data,omitempty"`
5555

5656
// config path is the path where the cache was loaded from
57-
secretName string `yaml:"-" json:"-"`
58-
secretNamespace string `yaml:"-" json:"-"`
59-
60-
raw []byte `yaml:"-" json:"-"`
61-
accessMutex sync.Mutex `yaml:"-" json:"-"`
57+
secretName string `yaml:"-" json:"-"`
58+
configName string `yaml:"-" json:"-"`
59+
secretNamespace string `yaml:"-" json:"-"`
60+
raw []byte `yaml:"-" json:"-"`
61+
accessMutex sync.Mutex `yaml:"-" json:"-"`
6262
}
6363

6464
type DevPodCache struct {
@@ -330,7 +330,12 @@ func (l *RemoteCache) Save(ctx context.Context, client kubectl.Client) error {
330330
ObjectMeta: metav1.ObjectMeta{
331331
Name: l.secretName,
332332
Namespace: client.Namespace(),
333+
Labels: map[string]string{
334+
"owner": "devspace",
335+
"name": l.configName,
336+
},
333337
},
338+
Type: SecretType,
334339
Data: map[string][]byte{
335340
"cache": data,
336341
},

pkg/devspace/dependency/resolver.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ func (r *resolver) resolveDependency(ctx *devspacecontext.Context, dependencyCon
175175
cloned.Vars = append(cloned.Vars, strings.TrimSpace(k)+"="+strings.TrimSpace(v))
176176
}
177177

178-
// Recreate client if necessary
178+
// recreate client if necessary
179179
client := ctx.KubeClient
180180
if dependency.Namespace != "" {
181181
if ctx.KubeClient == nil {

0 commit comments

Comments
 (0)