Commit d9ba19c7 authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #46468 from alexandercampbell/cleanup-in-kubectl

Automatic merge from submit-queue Cleanup pkg/kubectl I was reading through `pkg/kubectl` in preparation for completing https://github.com/kubernetes/kubectl/issues/11 and noticed several opportunities for improvement. This should be easy to review since it's mostly mechanical changes. The only complicated changes are in `addFromEnvFile`, which I refactored into two functions and wrote tests for. **Release note**: ```release-note NONE ```
parents a81c6592 ac793982
...@@ -14,6 +14,7 @@ go_test( ...@@ -14,6 +14,7 @@ go_test(
"cluster_test.go", "cluster_test.go",
"configmap_test.go", "configmap_test.go",
"deployment_test.go", "deployment_test.go",
"env_file_test.go",
"generate_test.go", "generate_test.go",
"kubectl_test.go", "kubectl_test.go",
"namespace_test.go", "namespace_test.go",
......
...@@ -61,11 +61,7 @@ func SetOriginalConfiguration(info *resource.Info, original []byte) error { ...@@ -61,11 +61,7 @@ func SetOriginalConfiguration(info *resource.Info, original []byte) error {
} }
annots[api.LastAppliedConfigAnnotation] = string(original) annots[api.LastAppliedConfigAnnotation] = string(original)
if err := info.Mapping.MetadataAccessor.SetAnnotations(info.Object, annots); err != nil { return info.Mapping.MetadataAccessor.SetAnnotations(info.Object, annots)
return err
}
return nil
} }
// GetModifiedConfiguration retrieves the modified configuration of the object. // GetModifiedConfiguration retrieves the modified configuration of the object.
......
...@@ -18,7 +18,7 @@ package cmd ...@@ -18,7 +18,7 @@ package cmd
import ( import (
"io" "io"
gruntime "runtime" "runtime"
"github.com/spf13/cobra" "github.com/spf13/cobra"
...@@ -96,7 +96,8 @@ func NewCmdApplyEditLastApplied(f cmdutil.Factory, out, errOut io.Writer) *cobra ...@@ -96,7 +96,8 @@ func NewCmdApplyEditLastApplied(f cmdutil.Factory, out, errOut io.Writer) *cobra
usage := "to use to edit the resource" usage := "to use to edit the resource"
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage) cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
cmd.Flags().StringVarP(&options.Output, "output", "o", "yaml", "Output format. One of: yaml|json.") cmd.Flags().StringVarP(&options.Output, "output", "o", "yaml", "Output format. One of: yaml|json.")
cmd.Flags().BoolVar(&options.WindowsLineEndings, "windows-line-endings", gruntime.GOOS == "windows", "Use Windows line-endings (default Unix line-endings)") cmd.Flags().BoolVar(&options.WindowsLineEndings, "windows-line-endings", runtime.GOOS == "windows",
"Defaults to the line ending native to your platform.")
cmdutil.AddRecordVarFlag(cmd, &options.Record) cmdutil.AddRecordVarFlag(cmd, &options.Record)
return cmd return cmd
......
...@@ -118,11 +118,7 @@ func (o *SetLastAppliedOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) ...@@ -118,11 +118,7 @@ func (o *SetLastAppliedOptions) Complete(f cmdutil.Factory, cmd *cobra.Command)
} }
o.Namespace, o.EnforceNamespace, err = f.DefaultNamespace() o.Namespace, o.EnforceNamespace, err = f.DefaultNamespace()
if err != nil { return err
return err
}
return nil
} }
func (o *SetLastAppliedOptions) Validate(f cmdutil.Factory, cmd *cobra.Command) error { func (o *SetLastAppliedOptions) Validate(f cmdutil.Factory, cmd *cobra.Command) error {
...@@ -179,10 +175,7 @@ func (o *SetLastAppliedOptions) Validate(f cmdutil.Factory, cmd *cobra.Command) ...@@ -179,10 +175,7 @@ func (o *SetLastAppliedOptions) Validate(f cmdutil.Factory, cmd *cobra.Command)
return nil return nil
}) })
if err != nil { return err
return err
}
return nil
} }
func (o *SetLastAppliedOptions) RunSetLastApplied(f cmdutil.Factory, cmd *cobra.Command) error { func (o *SetLastAppliedOptions) RunSetLastApplied(f cmdutil.Factory, cmd *cobra.Command) error {
......
...@@ -158,11 +158,7 @@ func (o *ConvertOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.C ...@@ -158,11 +158,7 @@ func (o *ConvertOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.C
} }
o.encoder = f.JSONEncoder() o.encoder = f.JSONEncoder()
o.printer, err = f.PrinterForCommand(cmd, o.local, nil, printers.PrintOptions{}) o.printer, err = f.PrinterForCommand(cmd, o.local, nil, printers.PrintOptions{})
if err != nil { return err
return err
}
return nil
} }
// RunConvert implements the generic Convert command // RunConvert implements the generic Convert command
......
...@@ -34,15 +34,15 @@ import ( ...@@ -34,15 +34,15 @@ import (
) )
var ( var (
cp_example = templates.Examples(i18n.T(` cpExample = templates.Examples(i18n.T(`
# !!!Important Note!!! # !!!Important Note!!!
# Requires that the 'tar' binary is present in your container # Requires that the 'tar' binary is present in your container
# image. If 'tar' is not present, 'kubectl cp' will fail. # image. If 'tar' is not present, 'kubectl cp' will fail.
# Copy /tmp/foo_dir local directory to /tmp/bar_dir in a remote pod in the default namespace # Copy /tmp/foo_dir local directory to /tmp/bar_dir in a remote pod in the default namespace
kubectl cp /tmp/foo_dir <some-pod>:/tmp/bar_dir kubectl cp /tmp/foo_dir <some-pod>:/tmp/bar_dir
# Copy /tmp/foo local file to /tmp/bar in a remote pod in a specific container # Copy /tmp/foo local file to /tmp/bar in a remote pod in a specific container
kubectl cp /tmp/foo <some-pod>:/tmp/bar -c <specific-container> kubectl cp /tmp/foo <some-pod>:/tmp/bar -c <specific-container>
# Copy /tmp/foo local file to /tmp/bar in a remote pod in namespace <some-namespace> # Copy /tmp/foo local file to /tmp/bar in a remote pod in namespace <some-namespace>
...@@ -52,8 +52,8 @@ var ( ...@@ -52,8 +52,8 @@ var (
kubectl cp <some-namespace>/<some-pod>:/tmp/foo /tmp/bar`)) kubectl cp <some-namespace>/<some-pod>:/tmp/foo /tmp/bar`))
cpUsageStr = dedent.Dedent(` cpUsageStr = dedent.Dedent(`
expected 'cp <file-spec-src> <file-spec-dest> [-c container]'. expected 'cp <file-spec-src> <file-spec-dest> [-c container]'.
<file-spec> is: <file-spec> is:
[namespace/]pod-name:/file/path for a remote file [namespace/]pod-name:/file/path for a remote file
/file/path for a local file`) /file/path for a local file`)
) )
...@@ -64,7 +64,7 @@ func NewCmdCp(f cmdutil.Factory, cmdOut, cmdErr io.Writer) *cobra.Command { ...@@ -64,7 +64,7 @@ func NewCmdCp(f cmdutil.Factory, cmdOut, cmdErr io.Writer) *cobra.Command {
Use: "cp <file-spec-src> <file-spec-dest>", Use: "cp <file-spec-src> <file-spec-dest>",
Short: i18n.T("Copy files and directories to and from containers."), Short: i18n.T("Copy files and directories to and from containers."),
Long: "Copy files and directories to and from containers.", Long: "Copy files and directories to and from containers.",
Example: cp_example, Example: cpExample,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(runCopy(f, cmd, cmdOut, cmdErr, args)) cmdutil.CheckErr(runCopy(f, cmd, cmdOut, cmdErr, args))
}, },
......
...@@ -19,7 +19,7 @@ package cmd ...@@ -19,7 +19,7 @@ package cmd
import ( import (
"fmt" "fmt"
"io" "io"
gruntime "runtime" "runtime"
"github.com/spf13/cobra" "github.com/spf13/cobra"
...@@ -39,12 +39,12 @@ type CreateOptions struct { ...@@ -39,12 +39,12 @@ type CreateOptions struct {
} }
var ( var (
create_long = templates.LongDesc(i18n.T(` createLong = templates.LongDesc(i18n.T(`
Create a resource by filename or stdin. Create a resource from a file or from stdin.
JSON and YAML formats are accepted.`)) JSON and YAML formats are accepted.`))
create_example = templates.Examples(i18n.T(` createExample = templates.Examples(i18n.T(`
# Create a pod using the data in pod.json. # Create a pod using the data in pod.json.
kubectl create -f ./pod.json kubectl create -f ./pod.json
...@@ -60,9 +60,9 @@ func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command { ...@@ -60,9 +60,9 @@ func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "create -f FILENAME", Use: "create -f FILENAME",
Short: i18n.T("Create a resource by filename or stdin"), Short: i18n.T("Create a resource from a file or from stdin."),
Long: create_long, Long: createLong,
Example: create_example, Example: createExample,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
if cmdutil.IsFilenameEmpty(options.FilenameOptions.Filenames) { if cmdutil.IsFilenameEmpty(options.FilenameOptions.Filenames) {
defaultRunFunc := cmdutil.DefaultSubCommandRun(errOut) defaultRunFunc := cmdutil.DefaultSubCommandRun(errOut)
...@@ -80,7 +80,8 @@ func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command { ...@@ -80,7 +80,8 @@ func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
cmdutil.AddValidateFlags(cmd) cmdutil.AddValidateFlags(cmd)
cmdutil.AddPrinterFlags(cmd) cmdutil.AddPrinterFlags(cmd)
cmd.Flags().BoolVar(&options.EditBeforeCreate, "edit", false, "Edit the API resource before creating") cmd.Flags().BoolVar(&options.EditBeforeCreate, "edit", false, "Edit the API resource before creating")
cmd.Flags().Bool("windows-line-endings", gruntime.GOOS == "windows", "Only relevant if --edit=true. Use Windows line-endings (default Unix line-endings)") cmd.Flags().Bool("windows-line-endings", runtime.GOOS == "windows",
"Only relevant if --edit=true. Defaults to the line ending native to your platform.")
cmdutil.AddApplyAnnotationFlags(cmd) cmdutil.AddApplyAnnotationFlags(cmd)
cmdutil.AddRecordFlag(cmd) cmdutil.AddRecordFlag(cmd)
cmdutil.AddDryRunFlag(cmd) cmdutil.AddDryRunFlag(cmd)
......
...@@ -17,7 +17,6 @@ limitations under the License. ...@@ -17,7 +17,6 @@ limitations under the License.
package cmd package cmd
import ( import (
"fmt"
"io" "io"
"github.com/spf13/cobra" "github.com/spf13/cobra"
...@@ -77,7 +76,7 @@ func CreateClusterRoleBinding(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Co ...@@ -77,7 +76,7 @@ func CreateClusterRoleBinding(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Co
ServiceAccounts: cmdutil.GetFlagStringArray(cmd, "serviceaccount"), ServiceAccounts: cmdutil.GetFlagStringArray(cmd, "serviceaccount"),
} }
default: default:
return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not supported.", generatorName)) return errUnsupportedGenerator(cmd, generatorName)
} }
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
Name: name, Name: name,
......
...@@ -17,7 +17,6 @@ limitations under the License. ...@@ -17,7 +17,6 @@ limitations under the License.
package cmd package cmd
import ( import (
"fmt"
"io" "io"
"github.com/spf13/cobra" "github.com/spf13/cobra"
...@@ -97,7 +96,7 @@ func CreateConfigMap(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, ar ...@@ -97,7 +96,7 @@ func CreateConfigMap(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, ar
EnvFileSource: cmdutil.GetFlagString(cmd, "from-env-file"), EnvFileSource: cmdutil.GetFlagString(cmd, "from-env-file"),
} }
default: default:
return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not supported.", generatorName)) return errUnsupportedGenerator(cmd, generatorName)
} }
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
Name: name, Name: name,
......
...@@ -38,7 +38,9 @@ var ( ...@@ -38,7 +38,9 @@ var (
kubectl create deployment my-dep --image=busybox`)) kubectl create deployment my-dep --image=busybox`))
) )
// NewCmdCreateDeployment is a macro command to create a new deployment // NewCmdCreateDeployment is a macro command to create a new deployment.
// This command is better known to users as `kubectl create deployment`.
// Note that this command overlaps significantly with the `kubectl run` command.
func NewCmdCreateDeployment(f cmdutil.Factory, cmdOut, cmdErr io.Writer) *cobra.Command { func NewCmdCreateDeployment(f cmdutil.Factory, cmdOut, cmdErr io.Writer) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "deployment NAME --image=image [--dry-run]", Use: "deployment NAME --image=image [--dry-run]",
...@@ -47,7 +49,7 @@ func NewCmdCreateDeployment(f cmdutil.Factory, cmdOut, cmdErr io.Writer) *cobra. ...@@ -47,7 +49,7 @@ func NewCmdCreateDeployment(f cmdutil.Factory, cmdOut, cmdErr io.Writer) *cobra.
Long: deploymentLong, Long: deploymentLong,
Example: deploymentExample, Example: deploymentExample,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
err := CreateDeployment(f, cmdOut, cmdErr, cmd, args) err := createDeployment(f, cmdOut, cmdErr, cmd, args)
cmdutil.CheckErr(err) cmdutil.CheckErr(err)
}, },
} }
...@@ -60,8 +62,7 @@ func NewCmdCreateDeployment(f cmdutil.Factory, cmdOut, cmdErr io.Writer) *cobra. ...@@ -60,8 +62,7 @@ func NewCmdCreateDeployment(f cmdutil.Factory, cmdOut, cmdErr io.Writer) *cobra.
return cmd return cmd
} }
// CreateDeployment implements the behavior to run the create deployment command func createDeployment(f cmdutil.Factory, cmdOut, cmdErr io.Writer, cmd *cobra.Command, args []string) error {
func CreateDeployment(f cmdutil.Factory, cmdOut, cmdErr io.Writer, cmd *cobra.Command, args []string) error {
name, err := NameFromCommandArgs(cmd, args) name, err := NameFromCommandArgs(cmd, args)
if err != nil { if err != nil {
return err return err
...@@ -91,7 +92,7 @@ func CreateDeployment(f cmdutil.Factory, cmdOut, cmdErr io.Writer, cmd *cobra.Co ...@@ -91,7 +92,7 @@ func CreateDeployment(f cmdutil.Factory, cmdOut, cmdErr io.Writer, cmd *cobra.Co
case cmdutil.DeploymentBasicV1Beta1GeneratorName: case cmdutil.DeploymentBasicV1Beta1GeneratorName:
generator = &kubectl.DeploymentBasicGeneratorV1{Name: name, Images: cmdutil.GetFlagStringSlice(cmd, "image")} generator = &kubectl.DeploymentBasicGeneratorV1{Name: name, Images: cmdutil.GetFlagStringSlice(cmd, "image")}
default: default:
return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not supported.", generatorName)) return errUnsupportedGenerator(cmd, generatorName)
} }
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
Name: name, Name: name,
......
...@@ -80,6 +80,6 @@ func TestCreateDeploymentNoImage(t *testing.T) { ...@@ -80,6 +80,6 @@ func TestCreateDeploymentNoImage(t *testing.T) {
cmd := NewCmdCreateDeployment(f, buf, buf) cmd := NewCmdCreateDeployment(f, buf, buf)
cmd.Flags().Set("dry-run", "true") cmd.Flags().Set("dry-run", "true")
cmd.Flags().Set("output", "name") cmd.Flags().Set("output", "name")
err := CreateDeployment(f, buf, buf, cmd, []string{depName}) err := createDeployment(f, buf, buf, cmd, []string{depName})
assert.Error(t, err, "at least one image must be specified") assert.Error(t, err, "at least one image must be specified")
} }
...@@ -17,7 +17,6 @@ limitations under the License. ...@@ -17,7 +17,6 @@ limitations under the License.
package cmd package cmd
import ( import (
"fmt"
"io" "io"
"github.com/spf13/cobra" "github.com/spf13/cobra"
...@@ -69,7 +68,7 @@ func CreateNamespace(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, ar ...@@ -69,7 +68,7 @@ func CreateNamespace(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, ar
case cmdutil.NamespaceV1GeneratorName: case cmdutil.NamespaceV1GeneratorName:
generator = &kubectl.NamespaceGeneratorV1{Name: name} generator = &kubectl.NamespaceGeneratorV1{Name: name}
default: default:
return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not supported.", generatorName)) return errUnsupportedGenerator(cmd, generatorName)
} }
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
Name: name, Name: name,
......
...@@ -17,7 +17,6 @@ limitations under the License. ...@@ -17,7 +17,6 @@ limitations under the License.
package cmd package cmd
import ( import (
"fmt"
"io" "io"
"github.com/spf13/cobra" "github.com/spf13/cobra"
...@@ -89,7 +88,7 @@ func CreatePodDisruptionBudget(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.C ...@@ -89,7 +88,7 @@ func CreatePodDisruptionBudget(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.C
Selector: cmdutil.GetFlagString(cmd, "selector"), Selector: cmdutil.GetFlagString(cmd, "selector"),
} }
default: default:
return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not supported.", generatorName)) return errUnsupportedGenerator(cmd, generatorName)
} }
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
Name: name, Name: name,
......
...@@ -17,7 +17,6 @@ limitations under the License. ...@@ -17,7 +17,6 @@ limitations under the License.
package cmd package cmd
import ( import (
"fmt"
"io" "io"
"github.com/spf13/cobra" "github.com/spf13/cobra"
...@@ -78,7 +77,7 @@ func CreateQuota(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args [ ...@@ -78,7 +77,7 @@ func CreateQuota(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args [
Scopes: cmdutil.GetFlagString(cmd, "scopes"), Scopes: cmdutil.GetFlagString(cmd, "scopes"),
} }
default: default:
return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not supported.", generatorName)) return errUnsupportedGenerator(cmd, generatorName)
} }
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
Name: name, Name: name,
......
...@@ -17,7 +17,6 @@ limitations under the License. ...@@ -17,7 +17,6 @@ limitations under the License.
package cmd package cmd
import ( import (
"fmt"
"io" "io"
"github.com/spf13/cobra" "github.com/spf13/cobra"
...@@ -78,7 +77,7 @@ func CreateRoleBinding(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, ...@@ -78,7 +77,7 @@ func CreateRoleBinding(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command,
ServiceAccounts: cmdutil.GetFlagStringArray(cmd, "serviceaccount"), ServiceAccounts: cmdutil.GetFlagStringArray(cmd, "serviceaccount"),
} }
default: default:
return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not supported.", generatorName)) return errUnsupportedGenerator(cmd, generatorName)
} }
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
Name: name, Name: name,
......
...@@ -17,7 +17,6 @@ limitations under the License. ...@@ -17,7 +17,6 @@ limitations under the License.
package cmd package cmd
import ( import (
"fmt"
"io" "io"
"github.com/spf13/cobra" "github.com/spf13/cobra"
...@@ -110,7 +109,7 @@ func CreateSecretGeneric(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command ...@@ -110,7 +109,7 @@ func CreateSecretGeneric(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command
EnvFileSource: cmdutil.GetFlagString(cmd, "from-env-file"), EnvFileSource: cmdutil.GetFlagString(cmd, "from-env-file"),
} }
default: default:
return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not supported.", generatorName)) return errUnsupportedGenerator(cmd, generatorName)
} }
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
Name: name, Name: name,
...@@ -191,7 +190,7 @@ func CreateSecretDockerRegistry(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra. ...@@ -191,7 +190,7 @@ func CreateSecretDockerRegistry(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.
Server: cmdutil.GetFlagString(cmd, "docker-server"), Server: cmdutil.GetFlagString(cmd, "docker-server"),
} }
default: default:
return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not supported.", generatorName)) return errUnsupportedGenerator(cmd, generatorName)
} }
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
Name: name, Name: name,
...@@ -254,7 +253,7 @@ func CreateSecretTLS(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, ar ...@@ -254,7 +253,7 @@ func CreateSecretTLS(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, ar
Cert: cmdutil.GetFlagString(cmd, "cert"), Cert: cmdutil.GetFlagString(cmd, "cert"),
} }
default: default:
return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not supported.", generatorName)) return errUnsupportedGenerator(cmd, generatorName)
} }
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
Name: name, Name: name,
......
...@@ -17,7 +17,6 @@ limitations under the License. ...@@ -17,7 +17,6 @@ limitations under the License.
package cmd package cmd
import ( import (
"fmt"
"io" "io"
"github.com/spf13/cobra" "github.com/spf13/cobra"
...@@ -83,6 +82,10 @@ func NewCmdCreateServiceClusterIP(f cmdutil.Factory, cmdOut io.Writer) *cobra.Co ...@@ -83,6 +82,10 @@ func NewCmdCreateServiceClusterIP(f cmdutil.Factory, cmdOut io.Writer) *cobra.Co
return cmd return cmd
} }
func errUnsupportedGenerator(cmd *cobra.Command, generatorName string) error {
return cmdutil.UsageError(cmd, "Generator %s not supported. ", generatorName)
}
// CreateServiceClusterIP implements the behavior to run the create service clusterIP command // CreateServiceClusterIP implements the behavior to run the create service clusterIP command
func CreateServiceClusterIP(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error { func CreateServiceClusterIP(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
name, err := NameFromCommandArgs(cmd, args) name, err := NameFromCommandArgs(cmd, args)
...@@ -99,7 +102,7 @@ func CreateServiceClusterIP(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Comm ...@@ -99,7 +102,7 @@ func CreateServiceClusterIP(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Comm
ClusterIP: cmdutil.GetFlagString(cmd, "clusterip"), ClusterIP: cmdutil.GetFlagString(cmd, "clusterip"),
} }
default: default:
return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not supported.", generatorName)) return errUnsupportedGenerator(cmd, generatorName)
} }
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
Name: name, Name: name,
...@@ -156,7 +159,7 @@ func CreateServiceNodePort(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Comma ...@@ -156,7 +159,7 @@ func CreateServiceNodePort(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Comma
NodePort: cmdutil.GetFlagInt(cmd, "node-port"), NodePort: cmdutil.GetFlagInt(cmd, "node-port"),
} }
default: default:
return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not supported.", generatorName)) return errUnsupportedGenerator(cmd, generatorName)
} }
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
Name: name, Name: name,
...@@ -211,7 +214,7 @@ func CreateServiceLoadBalancer(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.C ...@@ -211,7 +214,7 @@ func CreateServiceLoadBalancer(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.C
ClusterIP: "", ClusterIP: "",
} }
default: default:
return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not supported.", generatorName)) return errUnsupportedGenerator(cmd, generatorName)
} }
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
Name: name, Name: name,
...@@ -272,7 +275,7 @@ func CreateExternalNameService(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.C ...@@ -272,7 +275,7 @@ func CreateExternalNameService(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.C
ClusterIP: "", ClusterIP: "",
} }
default: default:
return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not supported.", generatorName)) return errUnsupportedGenerator(cmd, generatorName)
} }
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
Name: name, Name: name,
......
...@@ -17,7 +17,6 @@ limitations under the License. ...@@ -17,7 +17,6 @@ limitations under the License.
package cmd package cmd
import ( import (
"fmt"
"io" "io"
"github.com/spf13/cobra" "github.com/spf13/cobra"
...@@ -69,7 +68,7 @@ func CreateServiceAccount(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Comman ...@@ -69,7 +68,7 @@ func CreateServiceAccount(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Comman
case cmdutil.ServiceAccountV1GeneratorName: case cmdutil.ServiceAccountV1GeneratorName:
generator = &kubectl.ServiceAccountGeneratorV1{Name: name} generator = &kubectl.ServiceAccountGeneratorV1{Name: name}
default: default:
return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not supported.", generatorName)) return errUnsupportedGenerator(cmd, generatorName)
} }
return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
Name: name, Name: name,
......
...@@ -327,7 +327,7 @@ func deleteResource(info *resource.Info, out io.Writer, shortOutput bool, mapper ...@@ -327,7 +327,7 @@ func deleteResource(info *resource.Info, out io.Writer, shortOutput bool, mapper
return nil return nil
} }
// objectDeletionWaitInterval is the interval to wait between checks for deletion. Exposed for testing. // objectDeletionWaitInterval is the interval to wait between checks for deletion.
var objectDeletionWaitInterval = time.Second var objectDeletionWaitInterval = time.Second
// waitForObjectDeletion refreshes the object, waiting until it is deleted, a timeout is reached, or // waitForObjectDeletion refreshes the object, waiting until it is deleted, a timeout is reached, or
......
...@@ -19,7 +19,7 @@ package cmd ...@@ -19,7 +19,7 @@ package cmd
import ( import (
"fmt" "fmt"
"io" "io"
gruntime "runtime" "runtime"
"github.com/spf13/cobra" "github.com/spf13/cobra"
...@@ -108,7 +108,9 @@ func NewCmdEdit(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command { ...@@ -108,7 +108,9 @@ func NewCmdEdit(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
cmdutil.AddValidateOptionFlags(cmd, &options.ValidateOptions) cmdutil.AddValidateOptionFlags(cmd, &options.ValidateOptions)
cmd.Flags().StringVarP(&options.Output, "output", "o", "yaml", "Output format. One of: yaml|json.") cmd.Flags().StringVarP(&options.Output, "output", "o", "yaml", "Output format. One of: yaml|json.")
cmd.Flags().BoolVar(&options.WindowsLineEndings, "windows-line-endings", gruntime.GOOS == "windows", "Use Windows line-endings (default Unix line-endings)") cmd.Flags().BoolVar(&options.WindowsLineEndings, "windows-line-endings", runtime.GOOS == "windows",
"Defaults to the line ending native to your platform.")
cmdutil.AddApplyAnnotationVarFlags(cmd, &options.ApplyAnnotation) cmdutil.AddApplyAnnotationVarFlags(cmd, &options.ApplyAnnotation)
cmdutil.AddRecordVarFlag(cmd, &options.Record) cmdutil.AddRecordVarFlag(cmd, &options.Record)
cmdutil.AddInclude3rdPartyVarFlags(cmd, &options.Include3rdParty) cmdutil.AddInclude3rdPartyVarFlags(cmd, &options.Include3rdParty)
......
...@@ -116,7 +116,7 @@ func TestEdit(t *testing.T) { ...@@ -116,7 +116,7 @@ func TestEdit(t *testing.T) {
if step.StepType != "edit" { if step.StepType != "edit" {
t.Fatalf("%s, step %d: expected edit step, got %s %s", name, i, req.Method, req.URL.Path) t.Fatalf("%s, step %d: expected edit step, got %s %s", name, i, req.Method, req.URL.Path)
} }
if bytes.Compare(body, expectedInput) != 0 { if !bytes.Equal(body, expectedInput) {
if updateInputFixtures { if updateInputFixtures {
// Convenience to allow recapturing the input and persisting it here // Convenience to allow recapturing the input and persisting it here
ioutil.WriteFile(inputFile, body, os.FileMode(0644)) ioutil.WriteFile(inputFile, body, os.FileMode(0644))
...@@ -139,7 +139,7 @@ func TestEdit(t *testing.T) { ...@@ -139,7 +139,7 @@ func TestEdit(t *testing.T) {
req.Method, req.URL.Path, req.Header.Get("Content-Type"), req.Method, req.URL.Path, req.Header.Get("Content-Type"),
) )
} }
if bytes.Compare(body, expectedInput) != 0 { if !bytes.Equal(body, expectedInput) {
if updateInputFixtures { if updateInputFixtures {
// Convenience to allow recapturing the input and persisting it here // Convenience to allow recapturing the input and persisting it here
ioutil.WriteFile(inputFile, body, os.FileMode(0644)) ioutil.WriteFile(inputFile, body, os.FileMode(0644))
......
...@@ -34,9 +34,9 @@ import ( ...@@ -34,9 +34,9 @@ import (
) )
var ( var (
expose_resources = `pod (po), service (svc), replicationcontroller (rc), deployment (deploy), replicaset (rs)` exposeResources = `pod (po), service (svc), replicationcontroller (rc), deployment (deploy), replicaset (rs)`
expose_long = templates.LongDesc(` exposeLong = templates.LongDesc(`
Expose a resource as a new Kubernetes service. Expose a resource as a new Kubernetes service.
Looks up a deployment, service, replica set, replication controller or pod by name and uses the selector Looks up a deployment, service, replica set, replication controller or pod by name and uses the selector
...@@ -48,9 +48,9 @@ var ( ...@@ -48,9 +48,9 @@ var (
Possible resources include (case insensitive): Possible resources include (case insensitive):
` + expose_resources) ` + exposeResources)
expose_example = templates.Examples(i18n.T(` exposeExample = templates.Examples(i18n.T(`
# Create a service for a replicated nginx, which serves on port 80 and connects to the containers on port 8000. # Create a service for a replicated nginx, which serves on port 80 and connects to the containers on port 8000.
kubectl expose rc nginx --port=80 --target-port=8000 kubectl expose rc nginx --port=80 --target-port=8000
...@@ -77,7 +77,7 @@ func NewCmdExposeService(f cmdutil.Factory, out io.Writer) *cobra.Command { ...@@ -77,7 +77,7 @@ func NewCmdExposeService(f cmdutil.Factory, out io.Writer) *cobra.Command {
options := &resource.FilenameOptions{} options := &resource.FilenameOptions{}
validArgs, argAliases := []string{}, []string{} validArgs, argAliases := []string{}, []string{}
resources := regexp.MustCompile(`\s*,`).Split(expose_resources, -1) resources := regexp.MustCompile(`\s*,`).Split(exposeResources, -1)
for _, r := range resources { for _, r := range resources {
validArgs = append(validArgs, strings.Fields(r)[0]) validArgs = append(validArgs, strings.Fields(r)[0])
argAliases = kubectl.ResourceAliases(validArgs) argAliases = kubectl.ResourceAliases(validArgs)
...@@ -86,8 +86,8 @@ func NewCmdExposeService(f cmdutil.Factory, out io.Writer) *cobra.Command { ...@@ -86,8 +86,8 @@ func NewCmdExposeService(f cmdutil.Factory, out io.Writer) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "expose (-f FILENAME | TYPE NAME) [--port=port] [--protocol=TCP|UDP] [--target-port=number-or-name] [--name=name] [--external-ip=external-ip-of-service] [--type=type]", Use: "expose (-f FILENAME | TYPE NAME) [--port=port] [--protocol=TCP|UDP] [--target-port=number-or-name] [--name=name] [--external-ip=external-ip-of-service] [--type=type]",
Short: i18n.T("Take a replication controller, service, deployment or pod and expose it as a new Kubernetes Service"), Short: i18n.T("Take a replication controller, service, deployment or pod and expose it as a new Kubernetes Service"),
Long: expose_long, Long: exposeLong,
Example: expose_example, Example: exposeExample,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
err := RunExpose(f, out, cmd, args, options) err := RunExpose(f, out, cmd, args, options)
cmdutil.CheckErr(err) cmdutil.CheckErr(err)
......
...@@ -289,8 +289,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [ ...@@ -289,8 +289,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
first = false first = false
return false, nil return false, nil
} }
err := printer.PrintObj(e.Object, out) return false, printer.PrintObj(e.Object, out)
return false, err
}) })
return err return err
}) })
......
...@@ -506,9 +506,7 @@ func extractResourceList(objs []runtime.Object) ([]runtime.Object, error) { ...@@ -506,9 +506,7 @@ func extractResourceList(objs []runtime.Object) ([]runtime.Object, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, item := range items { finalObjs = append(finalObjs, items...)
finalObjs = append(finalObjs, item)
}
} }
return finalObjs, nil return finalObjs, nil
} }
......
...@@ -308,7 +308,7 @@ func parseLabels(spec []string) (map[string]string, []string, error) { ...@@ -308,7 +308,7 @@ func parseLabels(spec []string) (map[string]string, []string, error) {
labels := map[string]string{} labels := map[string]string{}
var remove []string var remove []string
for _, labelSpec := range spec { for _, labelSpec := range spec {
if strings.Index(labelSpec, "=") != -1 { if strings.Contains(labelSpec, "=") {
parts := strings.Split(labelSpec, "=") parts := strings.Split(labelSpec, "=")
if len(parts) != 2 { if len(parts) != 2 {
return nil, nil, fmt.Errorf("invalid label spec: %v", labelSpec) return nil, nil, fmt.Errorf("invalid label spec: %v", labelSpec)
......
...@@ -95,7 +95,7 @@ func NewCmdRun(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *co ...@@ -95,7 +95,7 @@ func NewCmdRun(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *co
Example: runExample, Example: runExample,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
argsLenAtDash := cmd.ArgsLenAtDash() argsLenAtDash := cmd.ArgsLenAtDash()
err := Run(f, cmdIn, cmdOut, cmdErr, cmd, args, argsLenAtDash) err := RunRun(f, cmdIn, cmdOut, cmdErr, cmd, args, argsLenAtDash)
cmdutil.CheckErr(err) cmdutil.CheckErr(err)
}, },
} }
...@@ -136,7 +136,7 @@ func addRunFlags(cmd *cobra.Command) { ...@@ -136,7 +136,7 @@ func addRunFlags(cmd *cobra.Command) {
cmd.Flags().String("schedule", "", i18n.T("A schedule in the Cron format the job should be run with.")) cmd.Flags().String("schedule", "", i18n.T("A schedule in the Cron format the job should be run with."))
} }
func Run(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cobra.Command, args []string, argsLenAtDash int) error { func RunRun(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cobra.Command, args []string, argsLenAtDash int) error {
// Let kubectl run follow rules for `--`, see #13004 issue // Let kubectl run follow rules for `--`, see #13004 issue
if len(args) == 0 || argsLenAtDash == 0 { if len(args) == 0 || argsLenAtDash == 0 {
return cmdutil.UsageError(cmd, "NAME is required for run") return cmdutil.UsageError(cmd, "NAME is required for run")
......
...@@ -181,7 +181,7 @@ func TestRunArgsFollowDashRules(t *testing.T) { ...@@ -181,7 +181,7 @@ func TestRunArgsFollowDashRules(t *testing.T) {
cmd := NewCmdRun(f, os.Stdin, os.Stdout, os.Stderr) cmd := NewCmdRun(f, os.Stdin, os.Stdout, os.Stderr)
cmd.Flags().Set("image", "nginx") cmd.Flags().Set("image", "nginx")
cmd.Flags().Set("generator", "run/v1") cmd.Flags().Set("generator", "run/v1")
err := Run(f, os.Stdin, os.Stdout, os.Stderr, cmd, test.args, test.argsLenAtDash) err := RunRun(f, os.Stdin, os.Stdout, os.Stderr, cmd, test.args, test.argsLenAtDash)
if test.expectError && err == nil { if test.expectError && err == nil {
t.Errorf("unexpected non-error (%s)", test.name) t.Errorf("unexpected non-error (%s)", test.name)
} }
...@@ -438,7 +438,7 @@ func TestRunValidations(t *testing.T) { ...@@ -438,7 +438,7 @@ func TestRunValidations(t *testing.T) {
for flagName, flagValue := range test.flags { for flagName, flagValue := range test.flags {
cmd.Flags().Set(flagName, flagValue) cmd.Flags().Set(flagName, flagValue)
} }
err := Run(f, inBuf, outBuf, errBuf, cmd, test.args, cmd.ArgsLenAtDash()) err := RunRun(f, inBuf, outBuf, errBuf, cmd, test.args, cmd.ArgsLenAtDash())
if err != nil && len(test.expectedErr) > 0 { if err != nil && len(test.expectedErr) > 0 {
if !strings.Contains(err.Error(), test.expectedErr) { if !strings.Contains(err.Error(), test.expectedErr) {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
......
...@@ -178,7 +178,7 @@ func parseTaints(spec []string) ([]v1.Taint, []v1.Taint, error) { ...@@ -178,7 +178,7 @@ func parseTaints(spec []string) ([]v1.Taint, []v1.Taint, error) {
uniqueTaints := map[v1.TaintEffect]sets.String{} uniqueTaints := map[v1.TaintEffect]sets.String{}
for _, taintSpec := range spec { for _, taintSpec := range spec {
if strings.Index(taintSpec, "=") != -1 && strings.Index(taintSpec, ":") != -1 { if strings.Contains(taintSpec, "=") && strings.Contains(taintSpec, ":") {
newTaint, err := utiltaints.ParseTaint(taintSpec) newTaint, err := utiltaints.ParseTaint(taintSpec)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
...@@ -197,7 +197,7 @@ func parseTaints(spec []string) ([]v1.Taint, []v1.Taint, error) { ...@@ -197,7 +197,7 @@ func parseTaints(spec []string) ([]v1.Taint, []v1.Taint, error) {
} else if strings.HasSuffix(taintSpec, "-") { } else if strings.HasSuffix(taintSpec, "-") {
taintKey := taintSpec[:len(taintSpec)-1] taintKey := taintSpec[:len(taintSpec)-1]
var effect v1.TaintEffect var effect v1.TaintEffect
if strings.Index(taintKey, ":") != -1 { if strings.Contains(taintKey, ":") {
parts := strings.Split(taintKey, ":") parts := strings.Split(taintKey, ":")
taintKey = parts[0] taintKey = parts[0]
effect = v1.TaintEffect(parts[1]) effect = v1.TaintEffect(parts[1])
......
...@@ -107,11 +107,7 @@ func RunVersion(f cmdutil.Factory, out io.Writer, cmd *cobra.Command) error { ...@@ -107,11 +107,7 @@ func RunVersion(f cmdutil.Factory, out io.Writer, cmd *cobra.Command) error {
} }
if serverErr != nil { return serverErr
return serverErr
}
return nil
} }
func retrieveServerVersion(f cmdutil.Factory) (*apimachineryversion.Info, error) { func retrieveServerVersion(f cmdutil.Factory) (*apimachineryversion.Info, error) {
......
...@@ -14,7 +14,8 @@ See the License for the specific language governing permissions and ...@@ -14,7 +14,8 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
// Package kubectl is a set of libraries that are used by the kubectl command line tool. // Package kubectl provides the functions used by the kubectl command line tool
// They are separated out into a library to support unit testing. Most functionality should // under k8s.io/kubernetes/cmd. The functions are kept in this package to better
// be included in this package, and the main kubectl should really just be an entry point. // support unit testing. The main() method for kubectl is only an entry point
// and should contain no functionality.
package kubectl // import "k8s.io/kubernetes/pkg/kubectl" package kubectl // import "k8s.io/kubernetes/pkg/kubectl"
...@@ -28,6 +28,47 @@ import ( ...@@ -28,6 +28,47 @@ import (
"k8s.io/apimachinery/pkg/util/validation" "k8s.io/apimachinery/pkg/util/validation"
) )
var utf8bom = []byte{0xEF, 0xBB, 0xBF}
// proccessEnvFileLine returns a blank key if the line is empty or a comment.
// The value will be retrieved from the environment if necessary.
func proccessEnvFileLine(line []byte, filePath string,
currentLine int) (key, value string, err error) {
if !utf8.Valid(line) {
return ``, ``, fmt.Errorf("env file %s contains invalid utf8 bytes at line %d: %v",
filePath, currentLine+1, line)
}
// We trim UTF8 BOM from the first line of the file but no others
if currentLine == 0 {
line = bytes.TrimPrefix(line, utf8bom)
}
// trim the line from all leading whitespace first
line = bytes.TrimLeftFunc(line, unicode.IsSpace)
// If the line is empty or a comment, we return a blank key/value pair.
if len(line) == 0 || line[0] == '#' {
return ``, ``, nil
}
data := strings.SplitN(string(line), "=", 2)
key = data[0]
if errs := validation.IsCIdentifier(key); len(errs) != 0 {
return ``, ``, fmt.Errorf("%q is not a valid key name: %s", key, strings.Join(errs, ";"))
}
if len(data) == 2 {
value = data[1]
} else {
// No value (no `=` in the line) is a signal to obtain the value
// from the environment.
value = os.Getenv(key)
}
return
}
// addFromEnvFile processes an env file allows a generic addTo to handle the // addFromEnvFile processes an env file allows a generic addTo to handle the
// collection of key value pairs or returns an error. // collection of key value pairs or returns an error.
func addFromEnvFile(filePath string, addTo func(key, value string) error) error { func addFromEnvFile(filePath string, addTo func(key, value string) error) error {
...@@ -39,38 +80,23 @@ func addFromEnvFile(filePath string, addTo func(key, value string) error) error ...@@ -39,38 +80,23 @@ func addFromEnvFile(filePath string, addTo func(key, value string) error) error
scanner := bufio.NewScanner(f) scanner := bufio.NewScanner(f)
currentLine := 0 currentLine := 0
utf8bom := []byte{0xEF, 0xBB, 0xBF}
for scanner.Scan() { for scanner.Scan() {
// Proccess the current line, retrieving a key/value pair if
// possible.
scannedBytes := scanner.Bytes() scannedBytes := scanner.Bytes()
if !utf8.Valid(scannedBytes) { key, value, err := proccessEnvFileLine(scannedBytes, filePath, currentLine)
return fmt.Errorf("env file %s contains invalid utf8 bytes at line %d: %v", filePath, currentLine+1, scannedBytes) if err != nil {
return err
} }
// We trim UTF8 BOM
if currentLine == 0 {
scannedBytes = bytes.TrimPrefix(scannedBytes, utf8bom)
}
// trim the line from all leading whitespace first
line := strings.TrimLeftFunc(string(scannedBytes), unicode.IsSpace)
currentLine++ currentLine++
// line is not empty, and not starting with '#'
if len(line) > 0 && !strings.HasPrefix(line, "#") { if len(key) == 0 {
data := strings.SplitN(line, "=", 2) // no key means line was empty or a comment
key := data[0] continue
if errs := validation.IsCIdentifier(key); len(errs) != 0 { }
return fmt.Errorf("%q is not a valid key name: %s", key, strings.Join(errs, ";"))
} if err = addTo(key, value); err != nil {
return err
value := ""
if len(data) > 1 {
// pass the value through, no trimming
value = data[1]
} else {
// a pass-through variable is given
value = os.Getenv(key)
}
if err = addTo(key, value); err != nil {
return err
}
} }
} }
return nil return nil
......
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package kubectl
import (
"os"
"strings"
"testing"
)
// Test the cases of proccessEnvFileLine that can be run without touching the
// environment.
func Test_processEnvFileLine(t *testing.T) {
testCases := []struct {
name string
line []byte
currentLine int
expectedKey string
expectedValue string
expectedErr string
}{
{"the utf8bom is trimmed on the first line",
append(utf8bom, 'a', '=', 'c'), 0, "a", "c", ""},
{"the utf8bom is NOT trimmed on the second line",
append(utf8bom, 'a', '=', 'c'), 1, "", "", "not a valid key name"},
{"no key is returned on a comment line",
[]byte{' ', '#', 'c'}, 0, "", "", ""},
{"no key is returned on a blank line",
[]byte{' ', ' ', '\t'}, 0, "", "", ""},
{"key is returned even with no value",
[]byte{' ', 'x', '='}, 0, "x", "", ""},
}
for _, c := range testCases {
key, value, err := proccessEnvFileLine(c.line, `filename`, c.currentLine)
t.Logf("Testing that %s.", c.name)
if c.expectedKey != key {
t.Errorf("\texpected key %q, received %q", c.expectedKey, key)
}
if c.expectedValue != value {
t.Errorf("\texpected value %q, received %q", c.expectedValue, value)
}
if len(c.expectedErr) == 0 {
if err != nil {
t.Errorf("\tunexpected err %v", err)
}
} else {
if !strings.Contains(err.Error(), c.expectedErr) {
t.Errorf("\terr %v doesn't match expected %q", err, c.expectedErr)
}
}
}
}
// proccessEnvFileLine needs to fetch the value from the environment if no
// equals sign is provided.
// For example:
//
// my_key1=alpha
// my_key2=beta
// my_key3
//
// In this file, my_key3 must be fetched from the environment.
// Test this capability.
func Test_processEnvFileLine_readEnvironment(t *testing.T) {
const realKey = "k8s_test_env_file_key"
const realValue = `my_value`
// Just in case, these two lines ensure the environment is restored to
// its original state.
original := os.Getenv(realKey)
defer func() { os.Setenv(realKey, original) }()
os.Setenv(realKey, `my_value`)
key, value, err := proccessEnvFileLine([]byte(realKey), `filename`, 3)
if err != nil {
t.Fatal(err)
}
if key != realKey {
t.Errorf(`expected key %q, received %q`, realKey, key)
}
if value != realValue {
t.Errorf(`expected value %q, received %q`, realValue, value)
}
}
...@@ -35,7 +35,9 @@ type GeneratorParam struct { ...@@ -35,7 +35,9 @@ type GeneratorParam struct {
Required bool Required bool
} }
// Generator is an interface for things that can generate API objects from input parameters. // Generator is an interface for things that can generate API objects from input
// parameters. One example is the "expose" generator that is capable of exposing
// new replication controllers and services, among other things.
type Generator interface { type Generator interface {
// Generate creates an API object given a set of parameters // Generate creates an API object given a set of parameters
Generate(params map[string]interface{}) (runtime.Object, error) Generate(params map[string]interface{}) (runtime.Object, error)
......
...@@ -212,7 +212,10 @@ func parseFileSource(source string) (keyName, filePath string, err error) { ...@@ -212,7 +212,10 @@ func parseFileSource(source string) (keyName, filePath string, err error) {
} }
} }
// parseLiteralSource parses the source key=val pair // parseLiteralSource parses the source key=val pair into its component pieces.
// This functionality is distinguished from strings.SplitN(source, "=", 2) since
// it returns an error in the case of empty keys, values, or a missing equals
// sign.
func parseLiteralSource(source string) (keyName, value string, err error) { func parseLiteralSource(source string) (keyName, value string, err error) {
// leading equal is invalid // leading equal is invalid
if strings.Index(source, "=") == 0 { if strings.Index(source, "=") == 0 {
......
...@@ -108,7 +108,8 @@ func (f *FilterServer) accept(method, path, host string) bool { ...@@ -108,7 +108,8 @@ func (f *FilterServer) accept(method, path, host string) bool {
return false return false
} }
// Make a copy of f which passes requests along to the new delegate. // HandlerFor makes a shallow copy of f which passes its requests along to the
// new delegate.
func (f *FilterServer) HandlerFor(delegate http.Handler) *FilterServer { func (f *FilterServer) HandlerFor(delegate http.Handler) *FilterServer {
f2 := *f f2 := *f
f2.delegate = delegate f2.delegate = delegate
......
...@@ -565,10 +565,7 @@ func Rename(c coreclient.ReplicationControllersGetter, rc *api.ReplicationContro ...@@ -565,10 +565,7 @@ func Rename(c coreclient.ReplicationControllersGetter, rc *api.ReplicationContro
} }
// Then create the same RC with the new name. // Then create the same RC with the new name.
_, err = c.ReplicationControllers(rc.Namespace).Create(rc) _, err = c.ReplicationControllers(rc.Namespace).Create(rc)
if err != nil { return err
return err
}
return nil
} }
func LoadExistingNextReplicationController(c coreclient.ReplicationControllersGetter, namespace, newName string) (*api.ReplicationController, error) { func LoadExistingNextReplicationController(c coreclient.ReplicationControllersGetter, namespace, newName string) (*api.ReplicationController, error) {
...@@ -684,14 +681,14 @@ func UpdateExistingReplicationController(rcClient coreclient.ReplicationControll ...@@ -684,14 +681,14 @@ func UpdateExistingReplicationController(rcClient coreclient.ReplicationControll
if _, found := oldRc.Spec.Selector[deploymentKey]; !found { if _, found := oldRc.Spec.Selector[deploymentKey]; !found {
SetNextControllerAnnotation(oldRc, newName) SetNextControllerAnnotation(oldRc, newName)
return AddDeploymentKeyToReplicationController(oldRc, rcClient, podClient, deploymentKey, deploymentValue, namespace, out) return AddDeploymentKeyToReplicationController(oldRc, rcClient, podClient, deploymentKey, deploymentValue, namespace, out)
} else {
// If we didn't need to update the controller for the deployment key, we still need to write
// the "next" controller.
applyUpdate := func(rc *api.ReplicationController) {
SetNextControllerAnnotation(rc, newName)
}
return updateRcWithRetries(rcClient, namespace, oldRc, applyUpdate)
} }
// If we didn't need to update the controller for the deployment key, we still need to write
// the "next" controller.
applyUpdate := func(rc *api.ReplicationController) {
SetNextControllerAnnotation(rc, newName)
}
return updateRcWithRetries(rcClient, namespace, oldRc, applyUpdate)
} }
func AddDeploymentKeyToReplicationController(oldRc *api.ReplicationController, rcClient coreclient.ReplicationControllersGetter, podClient coreclient.PodsGetter, deploymentKey, deploymentValue, namespace string, out io.Writer) (*api.ReplicationController, error) { func AddDeploymentKeyToReplicationController(oldRc *api.ReplicationController, rcClient coreclient.ReplicationControllersGetter, podClient coreclient.PodsGetter, deploymentKey, deploymentValue, namespace string, out io.Writer) (*api.ReplicationController, error) {
......
...@@ -868,9 +868,3 @@ func parseEnvs(envArray []string) ([]v1.EnvVar, error) { ...@@ -868,9 +868,3 @@ func parseEnvs(envArray []string) ([]v1.EnvVar, error) {
} }
return envs, nil return envs, nil
} }
func newBool(val bool) *bool {
p := new(bool)
*p = val
return p
}
...@@ -46,11 +46,12 @@ const ( ...@@ -46,11 +46,12 @@ const (
Timeout = time.Minute * 5 Timeout = time.Minute * 5
) )
// A Reaper handles terminating an object as gracefully as possible. // A Reaper terminates an object as gracefully as possible.
// timeout is how long we'll wait for the termination to be successful
// gracePeriod is time given to an API object for it to delete itself cleanly,
// e.g., pod shutdown. It may or may not be supported by the API object.
type Reaper interface { type Reaper interface {
// Stop a given object within a namespace. timeout is how long we'll
// wait for the termination to be successful. gracePeriod is time given
// to an API object for it to delete itself cleanly (e.g., pod
// shutdown). It may or may not be supported by the API object.
Stop(namespace, name string, timeout time.Duration, gracePeriod *metav1.DeleteOptions) error Stop(namespace, name string, timeout time.Duration, gracePeriod *metav1.DeleteOptions) error
} }
...@@ -135,11 +136,6 @@ type StatefulSetReaper struct { ...@@ -135,11 +136,6 @@ type StatefulSetReaper struct {
pollInterval, timeout time.Duration pollInterval, timeout time.Duration
} }
type objInterface interface {
Delete(name string) error
Get(name string) (metav1.Object, error)
}
// getOverlappingControllers finds rcs that this controller overlaps, as well as rcs overlapping this controller. // getOverlappingControllers finds rcs that this controller overlaps, as well as rcs overlapping this controller.
func getOverlappingControllers(rcClient coreclient.ReplicationControllerInterface, rc *api.ReplicationController) ([]api.ReplicationController, error) { func getOverlappingControllers(rcClient coreclient.ReplicationControllerInterface, rc *api.ReplicationController) ([]api.ReplicationController, error) {
rcs, err := rcClient.List(metav1.ListOptions{}) rcs, err := rcClient.List(metav1.ListOptions{})
...@@ -336,6 +332,8 @@ func (reaper *StatefulSetReaper) Stop(namespace, name string, timeout time.Durat ...@@ -336,6 +332,8 @@ func (reaper *StatefulSetReaper) Stop(namespace, name string, timeout time.Durat
} }
if timeout == 0 { if timeout == 0 {
numReplicas := ss.Spec.Replicas numReplicas := ss.Spec.Replicas
// BUG: this timeout is never used.
timeout = Timeout + time.Duration(10*numReplicas)*time.Second timeout = Timeout + time.Duration(10*numReplicas)*time.Second
} }
retry := NewRetryParams(reaper.pollInterval, reaper.timeout) retry := NewRetryParams(reaper.pollInterval, reaper.timeout)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment