1/*
2Copyright 2018 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package add
18
19import (
20	"fmt"
21	"strings"
22
23	"sigs.k8s.io/kustomize/pkg/fs"
24)
25
26// flagsAndArgs encapsulates the options for add secret/configmap commands.
27type flagsAndArgs struct {
28	// Name of configMap/Secret (required)
29	Name string
30	// FileSources to derive the configMap/Secret from (optional)
31	FileSources []string
32	// LiteralSources to derive the configMap/Secret from (optional)
33	LiteralSources []string
34	// EnvFileSource to derive the configMap/Secret from (optional)
35	// TODO: Rationalize this name with Generic.EnvSource
36	EnvFileSource string
37	// Type of secret to create
38	Type string
39}
40
41// Validate validates required fields are set to support structured generation.
42func (a *flagsAndArgs) Validate(args []string) error {
43	if len(args) != 1 {
44		return fmt.Errorf("name must be specified once")
45	}
46	a.Name = args[0]
47	if len(a.EnvFileSource) == 0 && len(a.FileSources) == 0 && len(a.LiteralSources) == 0 {
48		return fmt.Errorf("at least from-env-file, or from-file or from-literal must be set")
49	}
50	if len(a.EnvFileSource) > 0 && (len(a.FileSources) > 0 || len(a.LiteralSources) > 0) {
51		return fmt.Errorf("from-env-file cannot be combined with from-file or from-literal")
52	}
53	// TODO: Should we check if the path exists? if it's valid, if it's within the same (sub-)directory?
54	return nil
55}
56
57// ExpandFileSource normalizes a string list, possibly
58// containing globs, into a validated, globless list.
59// For example, this list:
60//     some/path
61//     some/dir/a*
62//     bfile=some/dir/b*
63// becomes:
64//     some/path
65//     some/dir/airplane
66//     some/dir/ant
67//     some/dir/apple
68//     bfile=some/dir/banana
69// i.e. everything is converted to a key=value pair,
70// where the value is always a relative file path,
71// and the key, if missing, is the same as the value.
72// In the case where the key is explicitly declared,
73// the globbing, if present, must have exactly one match.
74func (a *flagsAndArgs) ExpandFileSource(fSys fs.FileSystem) error {
75	var results []string
76	for _, pattern := range a.FileSources {
77		var patterns []string
78		key := ""
79		// check if the pattern is in `--from-file=[key=]source` format
80		// and if so split it to send only the file-pattern to glob function
81		s := strings.Split(pattern, "=")
82		if len(s) == 2 {
83			patterns = append(patterns, s[1])
84			key = s[0]
85		} else {
86			patterns = append(patterns, s[0])
87		}
88		result, err := globPatterns(fSys, patterns)
89		if err != nil {
90			return err
91		}
92		// if the format is `--from-file=[key=]source` accept only one result
93		// and extend it with the `key=` prefix
94		if key != "" {
95			if len(result) != 1 {
96				return fmt.Errorf(
97					"'pattern '%s' catches files %v, should catch only one", pattern, result)
98			}
99			fileSource := fmt.Sprintf("%s=%s", key, result[0])
100			results = append(results, fileSource)
101		} else {
102			results = append(results, result...)
103		}
104	}
105	a.FileSources = results
106	return nil
107}
108