a3360680 |
)
type BuildSecretOptions struct {
Out io.Writer
Err io.Writer
Builder *resource.Builder
Infos []*resource.Info
Encoder runtime.Encoder
OutputVersion unversioned.GroupVersion
Filenames []string
Selector string
All bool
ShortOutput bool
Local bool
Mapper meta.RESTMapper
PrintObject func(runtime.Object) error
Secret string
Push bool
Pull bool
Source bool
Remove bool
}
// NewCmdBuildSecret implements the set build-secret command
func NewCmdBuildSecret(fullName string, f *clientcmd.Factory, out, errOut io.Writer) *cobra.Command {
options := &BuildSecretOptions{
Out: out,
Err: errOut,
}
cmd := &cobra.Command{
Use: "build-secret BUILDCONFIG SECRETNAME",
Short: "Update a build secret on a build config",
Long: buildSecretLong,
Example: fmt.Sprintf(buildSecretExample, fullName),
Run: func(cmd *cobra.Command, args []string) {
kcmdutil.CheckErr(options.Complete(f, cmd, args))
kcmdutil.CheckErr(options.Validate())
if err := options.Run(); err != nil {
// TODO: move me to kcmdutil
if err == cmdutil.ErrExit {
os.Exit(1)
}
kcmdutil.CheckErr(err)
}
},
}
kcmdutil.AddPrinterFlags(cmd)
cmd.Flags().StringVarP(&options.Selector, "selector", "l", options.Selector, "Selector (label query) to filter build configs")
cmd.Flags().BoolVar(&options.All, "all", options.All, "Select all build configs in the namespace")
cmd.Flags().StringSliceVarP(&options.Filenames, "filename", "f", options.Filenames, "Filename, directory, or URL to file to use to edit the resource.")
cmd.Flags().BoolVar(&options.Push, "push", options.Push, "If true, set the push secret on a build config")
cmd.Flags().BoolVar(&options.Pull, "pull", options.Pull, "If true, set the pull secret on a build config")
cmd.Flags().BoolVar(&options.Source, "source", options.Source, "If true, set the source secret on a build config")
cmd.Flags().BoolVar(&options.Remove, "remove", options.Remove, "If true, remove the build secret.")
cmd.Flags().BoolVar(&options.Local, "local", false, "If true, set build-secret will NOT contact api-server but run locally.")
cmd.MarkFlagFilename("filename", "yaml", "yml", "json")
return cmd
}
var supportedBuildTypes = []string{"buildconfigs"}
func (o *BuildSecretOptions) secretFromArg(f *clientcmd.Factory, mapper meta.RESTMapper, typer runtime.ObjectTyper, namespace, arg string) (string, error) {
builder := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), kapi.Codecs.UniversalDecoder()).
NamespaceParam(namespace).DefaultNamespace().
RequireObject(false).
ContinueOnError().
ResourceNames("secrets", arg).
Flatten()
var secretName string
err := builder.Do().Visit(func(info *resource.Info, err error) error {
if err != nil {
return err
}
if info.Mapping.Resource != "secrets" {
return fmt.Errorf("please specify a secret")
}
secretName = info.Name
return nil
})
if err != nil {
return "", err
}
return secretName, nil
}
func (o *BuildSecretOptions) Complete(f *clientcmd.Factory, cmd *cobra.Command, args []string) error {
var secretArg string
if !o.Remove {
if len(args) < 1 {
return kcmdutil.UsageError(cmd, "a secret name must be specified")
}
secretArg = args[len(args)-1]
args = args[:len(args)-1]
}
resources := args
if len(resources) == 0 && len(o.Selector) == 0 && len(o.Filenames) == 0 && !o.All {
return kcmdutil.UsageError(cmd, "one or more build configs must be specified as <name> or <resource>/<name>")
}
cmdNamespace, explicit, err := f.DefaultNamespace()
if err != nil {
return err
}
clientConfig, err := f.ClientConfig()
if err != nil {
return err
}
o.OutputVersion, err = kcmdutil.OutputVersion(cmd, clientConfig.GroupVersion)
if err != nil {
return err
}
mapper, typer := f.Object(false)
if len(secretArg) > 0 {
o.Secret, err = o.secretFromArg(f, mapper, typer, cmdNamespace, secretArg)
if err != nil {
return err
}
}
o.Builder = resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), kapi.Codecs.UniversalDecoder()).
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(explicit, false, o.Filenames...).
Flatten()
if !o.Local {
o.Builder = o.Builder.
ResourceNames("buildconfigs", resources...).
SelectorParam(o.Selector).
Latest()
if o.All {
o.Builder.ResourceTypes(supportedBuildTypes...).SelectAllParam(o.All)
}
}
output := kcmdutil.GetFlagString(cmd, "output")
if len(output) != 0 || o.Local {
o.PrintObject = func(obj runtime.Object) error { return f.PrintObject(cmd, mapper, obj, o.Out) }
}
o.Encoder = f.JSONEncoder()
o.ShortOutput = kcmdutil.GetFlagString(cmd, "output") == "name"
o.Mapper = mapper
return nil
}
func (o *BuildSecretOptions) Validate() error {
if !o.Pull && !o.Push && !o.Source {
return fmt.Errorf("specify the type of secret to set (--push, --pull, or --source)")
}
if !o.Remove && len(o.Secret) == 0 {
return fmt.Errorf("specify a secret to set")
}
if o.Remove && len(o.Secret) > 0 {
return fmt.Errorf("a secret cannot be specified when using the --remove flag")
}
return nil
}
func (o *BuildSecretOptions) Run() error {
infos := o.Infos
singular := len(o.Infos) <= 1
if o.Builder != nil {
loaded, err := o.Builder.Do().IntoSingular(&singular).Infos()
if err != nil {
return err
}
infos = loaded
}
patches := CalculatePatches(infos, o.Encoder, func(info *resource.Info) (bool, error) {
return o.setBuildSecret(info.Object)
})
if singular && len(patches) == 0 {
return fmt.Errorf("cannot set a build secret on %s/%s", infos[0].Mapping.Resource, infos[0].Name)
}
if o.PrintObject != nil {
object, err := resource.AsVersionedObject(infos, !singular, o.OutputVersion, kapi.Codecs.LegacyCodec(o.OutputVersion))
if err != nil {
return err
}
return o.PrintObject(object)
}
errs := []error{}
for _, patch := range patches {
info := patch.Info
if patch.Err != nil {
errs = append(errs, fmt.Errorf("%s/%s %v", info.Mapping.Resource, info.Name, patch.Err))
continue
}
if string(patch.Patch) == "{}" || len(patch.Patch) == 0 {
fmt.Fprintf(o.Err, "info: %s %q was not changed\n", info.Mapping.Resource, info.Name)
continue
}
obj, err := resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, kapi.StrategicMergePatchType, patch.Patch)
if err != nil {
errs = append(errs, fmt.Errorf("%s/%s %v", info.Mapping.Resource, info.Name, err))
continue
}
info.Refresh(obj, true)
kcmdutil.PrintSuccess(o.Mapper, o.ShortOutput, o.Out, info.Mapping.Resource, info.Name, "updated")
}
if len(errs) > 0 {
return errors.NewAggregate(errs)
}
return nil
}
// setBuildSecret will set a secret on an object. For now the only supported
// object type is BuildConfig.
func (o *BuildSecretOptions) setBuildSecret(obj runtime.Object) (bool, error) {
switch buildObj := obj.(type) {
case *buildapi.BuildConfig:
o.updateBuildConfig(buildObj)
return true, nil
default:
return false, nil
}
}
func (o *BuildSecretOptions) updateBuildConfig(bc *buildapi.BuildConfig) {
if o.Push {
if o.Remove {
bc.Spec.Output.PushSecret = nil
} else {
bc.Spec.Output.PushSecret = &kapi.LocalObjectReference{
Name: o.Secret,
}
}
}
if o.Pull {
switch {
case bc.Spec.Strategy.DockerStrategy != nil:
if o.Remove {
bc.Spec.Strategy.DockerStrategy.PullSecret = nil
} else {
bc.Spec.Strategy.DockerStrategy.PullSecret = &kapi.LocalObjectReference{
Name: o.Secret,
}
}
case bc.Spec.Strategy.SourceStrategy != nil:
if o.Remove {
bc.Spec.Strategy.SourceStrategy.PullSecret = nil
} else {
bc.Spec.Strategy.SourceStrategy.PullSecret = &kapi.LocalObjectReference{
Name: o.Secret,
}
}
case bc.Spec.Strategy.CustomStrategy != nil:
if o.Remove {
bc.Spec.Strategy.CustomStrategy.PullSecret = nil
} else {
bc.Spec.Strategy.CustomStrategy.PullSecret = &kapi.LocalObjectReference{
Name: o.Secret,
}
}
}
}
if o.Source {
if o.Remove {
bc.Spec.Source.SourceSecret = nil
} else {
bc.Spec.Source.SourceSecret = &kapi.LocalObjectReference{
Name: o.Secret,
}
}
}
} |