Skip to content

Commit 540a4a0

Browse files
authored
add skaffold inspect build-env add cluster command (#5849)
* add build-env add cluster command * remove unnecessary fields and fix pointer issue * add tests, fix typo
1 parent a26b947 commit 540a4a0

File tree

5 files changed

+618
-12
lines changed

5 files changed

+618
-12
lines changed

cmd/skaffold/app/cmd/inspect_build_env.go

+79-4
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,31 @@ import (
2828
)
2929

3030
var buildEnvFlags = struct {
31-
profile string
31+
profile string
32+
33+
// Common
34+
timeout string
35+
concurrency int
36+
37+
// Google Cloud Build
3238
projectID string
3339
diskSizeGb int64
3440
machineType string
35-
timeout string
36-
concurrency int
41+
42+
// Cluster (kaniko)
43+
pullSecretPath string
44+
pullSecretName string
45+
pullSecretMountPath string
46+
namespace string
47+
48+
dockerConfigPath string
49+
dockerConfigSecretName string
50+
51+
serviceAccount string
52+
runAsUser int64
53+
54+
randomPullSecret bool
55+
randomDockerConigSecret bool
3756
}{}
3857

3958
func cmdBuildEnv() *cobra.Command {
@@ -55,7 +74,7 @@ func cmdBuildEnvAdd() *cobra.Command {
5574
return NewCmd("add").
5675
WithDescription("Add a new build environment to the default pipeline or to a new or existing profile.").
5776
WithPersistentFlagAdder(cmdBuildEnvAddFlags).
58-
WithCommands(cmdBuildEnvAddGcb())
77+
WithCommands(cmdBuildEnvAddGcb(), cmdBuildEnvAddCluster())
5978
}
6079

6180
func cmdBuildEnvAddGcb() *cobra.Command {
@@ -70,6 +89,18 @@ Use the '--module' filter to specify the individual module to target. Otherwise,
7089
NoArgs(addGcbBuildEnv)
7190
}
7291

92+
func cmdBuildEnvAddCluster() *cobra.Command {
93+
return NewCmd("cluster").
94+
WithDescription("Add a new Cluster build environment definition").
95+
WithLongDescription(`Add a new Cluster build environment definition.
96+
Without the '--profile' flag the new environment definition is added to the default pipeline. With the '--profile' flag it will create a new profile with this build env definition.
97+
In these respective scenarios, it will fail if the build env definition for the default pipeline or the named profile already exists. To override an existing definition use 'skaffold inspect build-env modify' command instead.
98+
Use the '--module' filter to specify the individual module to target. Otherwise, it'll be applied to all modules defined in the target file. Also, with the '--profile' flag if the target config imports other configs as dependencies, then the new profile will be recursively created in all the imported configs also.`).
99+
WithExample("Add a new profile named 'cluster' targeting the builder 'kaniko' using the Kubernetes secret 'my-secret'", "inspect build-env add cluster --profile cluster --pullSecretName my-secret -f skaffold.yaml").
100+
WithFlagAdder(cmdBuildEnvAddClusterFlags).
101+
NoArgs(addClusterBuildEnv)
102+
}
103+
73104
func listBuildEnv(ctx context.Context, out io.Writer) error {
74105
return buildEnv.PrintBuildEnvsList(ctx, out, printBuildEnvsListOptions())
75106
}
@@ -78,6 +109,10 @@ func addGcbBuildEnv(ctx context.Context, out io.Writer) error {
78109
return buildEnv.AddGcbBuildEnv(ctx, out, addGcbBuildEnvOptions())
79110
}
80111

112+
func addClusterBuildEnv(ctx context.Context, out io.Writer) error {
113+
return buildEnv.AddClusterBuildEnv(ctx, out, addClusterBuildEnvOptions())
114+
}
115+
81116
func cmdBuildEnvAddFlags(f *pflag.FlagSet) {
82117
f.StringVarP(&buildEnvFlags.profile, "profile", "p", "", `Profile name to add the new build env definition in. If the profile name doesn't exist then the profile will be created in all the target configs. If this flag is not specified then the build env is added to the default pipeline of the target configs.`)
83118
}
@@ -90,6 +125,25 @@ func cmdBuildEnvAddGcbFlags(f *pflag.FlagSet) {
90125
f.IntVar(&buildEnvFlags.concurrency, "concurrency", -1, `number of artifacts to build concurrently. 0 means "no-limit"`)
91126
}
92127

128+
func cmdBuildEnvAddClusterFlags(f *pflag.FlagSet) {
129+
f.StringVar(&buildEnvFlags.timeout, "timeout", "", `Build timeout (in seconds)`)
130+
f.IntVar(&buildEnvFlags.concurrency, "concurrency", -1, `number of artifacts to build concurrently. 0 means "no-limit"`)
131+
132+
f.StringVar(&buildEnvFlags.pullSecretPath, "pullSecretPath", "", "Path to the Google Cloud service account secret key file.")
133+
f.StringVar(&buildEnvFlags.pullSecretName, "pullSecretName", "", "Name of the Kubernetes secret for pulling base images and pushing the final image.")
134+
f.StringVar(&buildEnvFlags.pullSecretMountPath, "pullSecretMountPath", "", "Path the pull secret will be mounted at within the running container.")
135+
f.StringVar(&buildEnvFlags.namespace, "namespace", "", "Kubernetes namespace.")
136+
137+
f.StringVar(&buildEnvFlags.dockerConfigPath, "dockerConfigPath", "", "Path to the docker config.json.")
138+
f.StringVar(&buildEnvFlags.dockerConfigSecretName, "dockerConfigSecretName", "", "Kubernetes secret that contains the config.json Docker configuration.")
139+
140+
f.StringVar(&buildEnvFlags.serviceAccount, "serviceAccount", "", "Kubernetes service account to use for the pod.")
141+
f.Int64Var(&buildEnvFlags.runAsUser, "runAsUser", -1, "Defines the UID to request for running the container.")
142+
143+
f.BoolVar(&buildEnvFlags.randomPullSecret, "randomPullSecret", false, "Adds a random UUID postfix to the default name of the pull secret to facilitate parallel builds.")
144+
f.BoolVar(&buildEnvFlags.randomDockerConigSecret, "randomDockerConigSecret", false, "Adds a random UUID postfix to the default name of the docker secret to facilitate parallel builds.")
145+
}
146+
93147
func cmdBuildEnvFlags(f *pflag.FlagSet) {
94148
f.StringSliceVarP(&inspectFlags.modules, "module", "m", nil, "Names of modules to filter target action by.")
95149
}
@@ -123,3 +177,24 @@ func addGcbBuildEnvOptions() inspect.Options {
123177
},
124178
}
125179
}
180+
func addClusterBuildEnvOptions() inspect.Options {
181+
return inspect.Options{
182+
Filename: inspectFlags.fileName,
183+
OutFormat: inspectFlags.outFormat,
184+
Modules: inspectFlags.modules,
185+
BuildEnvOptions: inspect.BuildEnvOptions{
186+
PullSecretPath: buildEnvFlags.pullSecretPath,
187+
PullSecretName: buildEnvFlags.pullSecretName,
188+
PullSecretMountPath: buildEnvFlags.pullSecretMountPath,
189+
Namespace: buildEnvFlags.namespace,
190+
DockerConfigPath: buildEnvFlags.dockerConfigPath,
191+
DockerConfigSecretName: buildEnvFlags.dockerConfigSecretName,
192+
ServiceAccount: buildEnvFlags.serviceAccount,
193+
RunAsUser: buildEnvFlags.runAsUser,
194+
RandomPullSecret: buildEnvFlags.randomPullSecret,
195+
RandomDockerConfigSecret: buildEnvFlags.randomDockerConigSecret,
196+
Timeout: buildEnvFlags.timeout,
197+
Concurrency: buildEnvFlags.concurrency,
198+
},
199+
}
200+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
Copyright 2021 The Skaffold Authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package inspect
18+
19+
import (
20+
"context"
21+
"io"
22+
"reflect"
23+
24+
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/config"
25+
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/inspect"
26+
latestV1 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest/v1"
27+
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
28+
)
29+
30+
func AddClusterBuildEnv(ctx context.Context, out io.Writer, opts inspect.Options) error {
31+
formatter := inspect.OutputFormatter(out, opts.OutFormat)
32+
cfgs, err := inspect.ConfigSetFunc(config.SkaffoldOptions{ConfigurationFile: opts.Filename, ConfigurationFilter: opts.Modules, SkipConfigDefaults: true, MakePathsAbsolute: util.BoolPtr(false)})
33+
if err != nil {
34+
return formatter.WriteErr(err)
35+
}
36+
if opts.Profile == "" {
37+
// empty profile flag implies that the new build env needs to be added to the default pipeline.
38+
// for these cases, don't add the new env definition to any configs imported as dependencies.
39+
cfgs = cfgs.SelectRootConfigs()
40+
for _, cfg := range cfgs {
41+
if cfg.Build.Cluster != nil && !reflect.DeepEqual(cfg.Build.Cluster, &latestV1.ClusterDetails{}) {
42+
return formatter.WriteErr(inspect.BuildEnvAlreadyExists(inspect.BuildEnvs.Cluster, cfg.SourceFile, ""))
43+
}
44+
cfg.Build.GoogleCloudBuild = nil
45+
cfg.Build.LocalBuild = nil
46+
cfg.Build.Cluster = constructClusterDefinition(cfg.Build.Cluster, opts.BuildEnvOptions)
47+
}
48+
} else {
49+
for _, cfg := range cfgs {
50+
index := -1
51+
for i := range cfg.Profiles {
52+
if cfg.Profiles[i].Name == opts.Profile {
53+
index = i
54+
break
55+
}
56+
}
57+
if index < 0 {
58+
index = len(cfg.Profiles)
59+
cfg.Profiles = append(cfg.Profiles, latestV1.Profile{Name: opts.Profile})
60+
}
61+
if cfg.Profiles[index].Build.Cluster != nil && !reflect.DeepEqual(cfg.Profiles[index].Build.Cluster, &latestV1.ClusterDetails{}) {
62+
return formatter.WriteErr(inspect.BuildEnvAlreadyExists(inspect.BuildEnvs.Cluster, cfg.SourceFile, opts.Profile))
63+
}
64+
cfg.Profiles[index].Build.GoogleCloudBuild = nil
65+
cfg.Profiles[index].Build.LocalBuild = nil
66+
cfg.Profiles[index].Build.Cluster = constructClusterDefinition(cfg.Build.Cluster, opts.BuildEnvOptions)
67+
68+
addProfileActivationStanza(cfg, opts.Profile)
69+
}
70+
}
71+
return inspect.MarshalConfigSet(cfgs)
72+
}
73+
74+
func constructClusterDefinition(existing *latestV1.ClusterDetails, opts inspect.BuildEnvOptions) *latestV1.ClusterDetails {
75+
var b latestV1.ClusterDetails
76+
if existing != nil {
77+
b = *existing
78+
}
79+
if opts.PullSecretPath != "" {
80+
b.PullSecretPath = opts.PullSecretPath
81+
}
82+
if opts.PullSecretName != "" {
83+
b.PullSecretName = opts.PullSecretName
84+
}
85+
if opts.PullSecretMountPath != "" {
86+
b.PullSecretMountPath = opts.PullSecretMountPath
87+
}
88+
if opts.Namespace != "" {
89+
b.Namespace = opts.Namespace
90+
}
91+
if opts.DockerConfigPath != "" {
92+
if b.DockerConfig == nil {
93+
b.DockerConfig = &latestV1.DockerConfig{}
94+
}
95+
b.DockerConfig.Path = opts.DockerConfigPath
96+
}
97+
if opts.DockerConfigSecretName != "" {
98+
if b.DockerConfig == nil {
99+
b.DockerConfig = &latestV1.DockerConfig{}
100+
}
101+
b.DockerConfig.SecretName = opts.DockerConfigSecretName
102+
}
103+
if opts.ServiceAccount != "" {
104+
b.ServiceAccountName = opts.ServiceAccount
105+
}
106+
if opts.RunAsUser >= 0 {
107+
b.RunAsUser = &opts.RunAsUser
108+
}
109+
if opts.RandomPullSecret {
110+
b.RandomPullSecret = opts.RandomPullSecret
111+
}
112+
if !opts.RandomDockerConfigSecret {
113+
b.RandomPullSecret = opts.RandomPullSecret
114+
}
115+
if opts.Concurrency >= 0 {
116+
b.Concurrency = opts.Concurrency
117+
}
118+
if opts.Timeout != "" {
119+
b.Timeout = opts.Timeout
120+
}
121+
return &b
122+
}

0 commit comments

Comments
 (0)