diff --git a/.generated_docs b/.generated_docs
index b0742ad1e38..16233713186 100644
--- a/.generated_docs
+++ b/.generated_docs
@@ -20,6 +20,10 @@ docs/man/man1/kubectl-config-use-context.1
docs/man/man1/kubectl-config-view.1
docs/man/man1/kubectl-config.1
docs/man/man1/kubectl-convert.1
+docs/man/man1/kubectl-create-namespace.1
+docs/man/man1/kubectl-create-secret-docker-registry.1
+docs/man/man1/kubectl-create-secret-generic.1
+docs/man/man1/kubectl-create-secret.1
docs/man/man1/kubectl-create.1
docs/man/man1/kubectl-delete.1
docs/man/man1/kubectl-describe.1
@@ -58,6 +62,10 @@ docs/user-guide/kubectl/kubectl_config_use-context.md
docs/user-guide/kubectl/kubectl_config_view.md
docs/user-guide/kubectl/kubectl_convert.md
docs/user-guide/kubectl/kubectl_create.md
+docs/user-guide/kubectl/kubectl_create_namespace.md
+docs/user-guide/kubectl/kubectl_create_secret.md
+docs/user-guide/kubectl/kubectl_create_secret_docker-registry.md
+docs/user-guide/kubectl/kubectl_create_secret_generic.md
docs/user-guide/kubectl/kubectl_delete.md
docs/user-guide/kubectl/kubectl_describe.md
docs/user-guide/kubectl/kubectl_edit.md
diff --git a/contrib/completions/bash/kubectl b/contrib/completions/bash/kubectl
index 433960d95b0..ac79c6937a9 100644
--- a/contrib/completions/bash/kubectl
+++ b/contrib/completions/bash/kubectl
@@ -401,10 +401,204 @@ _kubectl_describe()
must_have_one_noun+=("serviceaccount")
}
+_kubectl_create_namespace()
+{
+ last_command="kubectl_create_namespace"
+ commands=()
+
+ flags=()
+ two_word_flags=()
+ flags_with_completion=()
+ flags_completion=()
+
+ flags+=("--dry-run")
+ flags+=("--generator=")
+ flags+=("--output=")
+ two_word_flags+=("-o")
+ flags+=("--output-version=")
+ flags+=("--save-config")
+ flags+=("--schema-cache-dir=")
+ flags+=("--validate")
+ flags+=("--alsologtostderr")
+ flags+=("--api-version=")
+ flags+=("--certificate-authority=")
+ flags+=("--client-certificate=")
+ flags+=("--client-key=")
+ flags+=("--cluster=")
+ flags+=("--context=")
+ flags+=("--insecure-skip-tls-verify")
+ flags+=("--kubeconfig=")
+ flags+=("--log-backtrace-at=")
+ flags+=("--log-dir=")
+ flags+=("--log-flush-frequency=")
+ flags+=("--logtostderr")
+ flags+=("--match-server-version")
+ flags+=("--namespace=")
+ flags+=("--password=")
+ flags+=("--server=")
+ two_word_flags+=("-s")
+ flags+=("--stderrthreshold=")
+ flags+=("--token=")
+ flags+=("--user=")
+ flags+=("--username=")
+ flags+=("--v=")
+ flags+=("--vmodule=")
+
+ must_have_one_flag=()
+ must_have_one_noun=()
+}
+
+_kubectl_create_secret_docker-registry()
+{
+ last_command="kubectl_create_secret_docker-registry"
+ commands=()
+
+ flags=()
+ two_word_flags=()
+ flags_with_completion=()
+ flags_completion=()
+
+ flags+=("--docker-email=")
+ flags+=("--docker-password=")
+ flags+=("--docker-server=")
+ flags+=("--docker-username=")
+ flags+=("--dry-run")
+ flags+=("--generator=")
+ flags+=("--output=")
+ two_word_flags+=("-o")
+ flags+=("--output-version=")
+ flags+=("--save-config")
+ flags+=("--schema-cache-dir=")
+ flags+=("--validate")
+ flags+=("--alsologtostderr")
+ flags+=("--api-version=")
+ flags+=("--certificate-authority=")
+ flags+=("--client-certificate=")
+ flags+=("--client-key=")
+ flags+=("--cluster=")
+ flags+=("--context=")
+ flags+=("--insecure-skip-tls-verify")
+ flags+=("--kubeconfig=")
+ flags+=("--log-backtrace-at=")
+ flags+=("--log-dir=")
+ flags+=("--log-flush-frequency=")
+ flags+=("--logtostderr")
+ flags+=("--match-server-version")
+ flags+=("--namespace=")
+ flags+=("--password=")
+ flags+=("--server=")
+ two_word_flags+=("-s")
+ flags+=("--stderrthreshold=")
+ flags+=("--token=")
+ flags+=("--user=")
+ flags+=("--username=")
+ flags+=("--v=")
+ flags+=("--vmodule=")
+
+ must_have_one_flag=()
+ must_have_one_flag+=("--docker-email=")
+ must_have_one_flag+=("--docker-password=")
+ must_have_one_flag+=("--docker-username=")
+ must_have_one_noun=()
+}
+
+_kubectl_create_secret_generic()
+{
+ last_command="kubectl_create_secret_generic"
+ commands=()
+
+ flags=()
+ two_word_flags=()
+ flags_with_completion=()
+ flags_completion=()
+
+ flags+=("--dry-run")
+ flags+=("--from-file=")
+ flags+=("--from-literal=")
+ flags+=("--generator=")
+ flags+=("--output=")
+ two_word_flags+=("-o")
+ flags+=("--output-version=")
+ flags+=("--save-config")
+ flags+=("--schema-cache-dir=")
+ flags+=("--type=")
+ flags+=("--validate")
+ flags+=("--alsologtostderr")
+ flags+=("--api-version=")
+ flags+=("--certificate-authority=")
+ flags+=("--client-certificate=")
+ flags+=("--client-key=")
+ flags+=("--cluster=")
+ flags+=("--context=")
+ flags+=("--insecure-skip-tls-verify")
+ flags+=("--kubeconfig=")
+ flags+=("--log-backtrace-at=")
+ flags+=("--log-dir=")
+ flags+=("--log-flush-frequency=")
+ flags+=("--logtostderr")
+ flags+=("--match-server-version")
+ flags+=("--namespace=")
+ flags+=("--password=")
+ flags+=("--server=")
+ two_word_flags+=("-s")
+ flags+=("--stderrthreshold=")
+ flags+=("--token=")
+ flags+=("--user=")
+ flags+=("--username=")
+ flags+=("--v=")
+ flags+=("--vmodule=")
+
+ must_have_one_flag=()
+ must_have_one_noun=()
+}
+
+_kubectl_create_secret()
+{
+ last_command="kubectl_create_secret"
+ commands=()
+ commands+=("docker-registry")
+ commands+=("generic")
+
+ flags=()
+ two_word_flags=()
+ flags_with_completion=()
+ flags_completion=()
+
+ flags+=("--alsologtostderr")
+ flags+=("--api-version=")
+ flags+=("--certificate-authority=")
+ flags+=("--client-certificate=")
+ flags+=("--client-key=")
+ flags+=("--cluster=")
+ flags+=("--context=")
+ flags+=("--insecure-skip-tls-verify")
+ flags+=("--kubeconfig=")
+ flags+=("--log-backtrace-at=")
+ flags+=("--log-dir=")
+ flags+=("--log-flush-frequency=")
+ flags+=("--logtostderr")
+ flags+=("--match-server-version")
+ flags+=("--namespace=")
+ flags+=("--password=")
+ flags+=("--server=")
+ two_word_flags+=("-s")
+ flags+=("--stderrthreshold=")
+ flags+=("--token=")
+ flags+=("--user=")
+ flags+=("--username=")
+ flags+=("--v=")
+ flags+=("--vmodule=")
+
+ must_have_one_flag=()
+ must_have_one_noun=()
+}
+
_kubectl_create()
{
last_command="kubectl_create"
commands=()
+ commands+=("namespace")
+ commands+=("secret")
flags=()
two_word_flags=()
diff --git a/docs/man/man1/kubectl-create-namespace.1 b/docs/man/man1/kubectl-create-namespace.1
new file mode 100644
index 00000000000..8b5f788bbfd
--- /dev/null
+++ b/docs/man/man1/kubectl-create-namespace.1
@@ -0,0 +1,164 @@
+.TH "KUBERNETES" "1" " kubernetes User Manuals" "Eric Paris" "Jan 2015" ""
+
+
+.SH NAME
+.PP
+kubectl create namespace \- Create a namespace with the specified name.
+
+
+.SH SYNOPSIS
+.PP
+\fBkubectl create namespace\fP [OPTIONS]
+
+
+.SH DESCRIPTION
+.PP
+Create a namespace with the specified name.
+
+
+.SH OPTIONS
+.PP
+\fB\-\-dry\-run\fP=false
+ If true, only print the object that would be sent, without sending it.
+
+.PP
+\fB\-\-generator\fP="namespace/v1"
+ The name of the API generator to use.
+
+.PP
+\fB\-o\fP, \fB\-\-output\fP=""
+ Output format. One of: json|yaml|wide|name|go\-template=...|go\-template\-file=...|jsonpath=...|jsonpath\-file=... See golang template [
+\[la]http://golang.org/pkg/text/template/#pkg-overview\[ra]] and jsonpath template [
+\[la]http://releases.k8s.io/HEAD/docs/user-guide/jsonpath.md\[ra]].
+
+.PP
+\fB\-\-output\-version\fP=""
+ Output the formatted object with the given version (default api\-version).
+
+.PP
+\fB\-\-save\-config\fP=false
+ If true, the configuration of current object will be saved in its annotation. This is useful when you want to perform kubectl apply on this object in the future.
+
+.PP
+\fB\-\-schema\-cache\-dir\fP="\~/.kube/schema"
+ If non\-empty, load/store cached API schemas in this directory, default is '$HOME/.kube/schema'
+
+.PP
+\fB\-\-validate\fP=true
+ If true, use a schema to validate the input before sending it
+
+
+.SH OPTIONS INHERITED FROM PARENT COMMANDS
+.PP
+\fB\-\-alsologtostderr\fP=false
+ log to standard error as well as files
+
+.PP
+\fB\-\-api\-version\fP=""
+ The API version to use when talking to the server
+
+.PP
+\fB\-\-certificate\-authority\fP=""
+ Path to a cert. file for the certificate authority.
+
+.PP
+\fB\-\-client\-certificate\fP=""
+ Path to a client certificate file for TLS.
+
+.PP
+\fB\-\-client\-key\fP=""
+ Path to a client key file for TLS.
+
+.PP
+\fB\-\-cluster\fP=""
+ The name of the kubeconfig cluster to use
+
+.PP
+\fB\-\-context\fP=""
+ The name of the kubeconfig context to use
+
+.PP
+\fB\-\-insecure\-skip\-tls\-verify\fP=false
+ If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.
+
+.PP
+\fB\-\-kubeconfig\fP=""
+ Path to the kubeconfig file to use for CLI requests.
+
+.PP
+\fB\-\-log\-backtrace\-at\fP=:0
+ when logging hits line file:N, emit a stack trace
+
+.PP
+\fB\-\-log\-dir\fP=""
+ If non\-empty, write log files in this directory
+
+.PP
+\fB\-\-log\-flush\-frequency\fP=5s
+ Maximum number of seconds between log flushes
+
+.PP
+\fB\-\-logtostderr\fP=true
+ log to standard error instead of files
+
+.PP
+\fB\-\-match\-server\-version\fP=false
+ Require server version to match client version
+
+.PP
+\fB\-\-namespace\fP=""
+ If present, the namespace scope for this CLI request.
+
+.PP
+\fB\-\-password\fP=""
+ Password for basic authentication to the API server.
+
+.PP
+\fB\-s\fP, \fB\-\-server\fP=""
+ The address and port of the Kubernetes API server
+
+.PP
+\fB\-\-stderrthreshold\fP=2
+ logs at or above this threshold go to stderr
+
+.PP
+\fB\-\-token\fP=""
+ Bearer token for authentication to the API server.
+
+.PP
+\fB\-\-user\fP=""
+ The name of the kubeconfig user to use
+
+.PP
+\fB\-\-username\fP=""
+ Username for basic authentication to the API server.
+
+.PP
+\fB\-\-v\fP=0
+ log level for V logs
+
+.PP
+\fB\-\-vmodule\fP=
+ comma\-separated list of pattern=N settings for file\-filtered logging
+
+
+.SH EXAMPLE
+.PP
+.RS
+
+.nf
+ # Create a new namespace named my\-namespace
+ $ kubectl create namespace my\-namespace
+
+.fi
+.RE
+
+
+.SH SEE ALSO
+.PP
+\fBkubectl\-create(1)\fP,
+
+
+.SH HISTORY
+.PP
+January 2015, Originally compiled by Eric Paris (eparis at redhat dot com) based on the kubernetes source material, but hopefully they have been automatically generated since!
diff --git a/docs/man/man1/kubectl-create-secret-docker-registry.1 b/docs/man/man1/kubectl-create-secret-docker-registry.1
new file mode 100644
index 00000000000..7565a64264f
--- /dev/null
+++ b/docs/man/man1/kubectl-create-secret-docker-registry.1
@@ -0,0 +1,195 @@
+.TH "KUBERNETES" "1" " kubernetes User Manuals" "Eric Paris" "Jan 2015" ""
+
+
+.SH NAME
+.PP
+kubectl create secret docker\-registry \- Create a secret for use with a Docker registry.
+
+
+.SH SYNOPSIS
+.PP
+\fBkubectl create secret docker\-registry\fP [OPTIONS]
+
+
+.SH DESCRIPTION
+.PP
+Create a new secret for use with Docker registries.
+
+.PP
+Dockercfg secrets are used to authenticate against Docker registries.
+
+.PP
+When using the Docker command line to push images, you can authenticate to a given registry by running
+ 'docker login DOCKER\_REGISTRY\_SERVER \-\-username=DOCKER\_USER \-\-password=DOCKER\_PASSWORD \-\-email=DOCKER\_EMAIL'.
+That produces a \~/.dockercfg file that is used by subsequent 'docker push' and 'docker pull' commands to
+authenticate to the registry.
+
+.PP
+When creating applications, you may have a Docker registry that requires authentication. In order for the
+nodes to pull images on your behalf, they have to have the credentials. You can provide this information
+by creating a dockercfg secret and attaching it to your service account.
+
+
+.SH OPTIONS
+.PP
+\fB\-\-docker\-email\fP=""
+ Email for Docker registry
+
+.PP
+\fB\-\-docker\-password\fP=""
+ Password for Docker registry authentication
+
+.PP
+\fB\-\-docker\-server\fP="
+\[la]https://index.docker.io/v1/"\[ra]
+ Server location for Docker registry
+
+.PP
+\fB\-\-docker\-username\fP=""
+ Username for Docker registry authentication
+
+.PP
+\fB\-\-dry\-run\fP=false
+ If true, only print the object that would be sent, without sending it.
+
+.PP
+\fB\-\-generator\fP="secret\-for\-docker\-registry/v1"
+ The name of the API generator to use.
+
+.PP
+\fB\-o\fP, \fB\-\-output\fP=""
+ Output format. One of: json|yaml|wide|name|go\-template=...|go\-template\-file=...|jsonpath=...|jsonpath\-file=... See golang template [
+\[la]http://golang.org/pkg/text/template/#pkg-overview\[ra]] and jsonpath template [
+\[la]http://releases.k8s.io/HEAD/docs/user-guide/jsonpath.md\[ra]].
+
+.PP
+\fB\-\-output\-version\fP=""
+ Output the formatted object with the given version (default api\-version).
+
+.PP
+\fB\-\-save\-config\fP=false
+ If true, the configuration of current object will be saved in its annotation. This is useful when you want to perform kubectl apply on this object in the future.
+
+.PP
+\fB\-\-schema\-cache\-dir\fP="\~/.kube/schema"
+ If non\-empty, load/store cached API schemas in this directory, default is '$HOME/.kube/schema'
+
+.PP
+\fB\-\-validate\fP=true
+ If true, use a schema to validate the input before sending it
+
+
+.SH OPTIONS INHERITED FROM PARENT COMMANDS
+.PP
+\fB\-\-alsologtostderr\fP=false
+ log to standard error as well as files
+
+.PP
+\fB\-\-api\-version\fP=""
+ The API version to use when talking to the server
+
+.PP
+\fB\-\-certificate\-authority\fP=""
+ Path to a cert. file for the certificate authority.
+
+.PP
+\fB\-\-client\-certificate\fP=""
+ Path to a client certificate file for TLS.
+
+.PP
+\fB\-\-client\-key\fP=""
+ Path to a client key file for TLS.
+
+.PP
+\fB\-\-cluster\fP=""
+ The name of the kubeconfig cluster to use
+
+.PP
+\fB\-\-context\fP=""
+ The name of the kubeconfig context to use
+
+.PP
+\fB\-\-insecure\-skip\-tls\-verify\fP=false
+ If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.
+
+.PP
+\fB\-\-kubeconfig\fP=""
+ Path to the kubeconfig file to use for CLI requests.
+
+.PP
+\fB\-\-log\-backtrace\-at\fP=:0
+ when logging hits line file:N, emit a stack trace
+
+.PP
+\fB\-\-log\-dir\fP=""
+ If non\-empty, write log files in this directory
+
+.PP
+\fB\-\-log\-flush\-frequency\fP=5s
+ Maximum number of seconds between log flushes
+
+.PP
+\fB\-\-logtostderr\fP=true
+ log to standard error instead of files
+
+.PP
+\fB\-\-match\-server\-version\fP=false
+ Require server version to match client version
+
+.PP
+\fB\-\-namespace\fP=""
+ If present, the namespace scope for this CLI request.
+
+.PP
+\fB\-\-password\fP=""
+ Password for basic authentication to the API server.
+
+.PP
+\fB\-s\fP, \fB\-\-server\fP=""
+ The address and port of the Kubernetes API server
+
+.PP
+\fB\-\-stderrthreshold\fP=2
+ logs at or above this threshold go to stderr
+
+.PP
+\fB\-\-token\fP=""
+ Bearer token for authentication to the API server.
+
+.PP
+\fB\-\-user\fP=""
+ The name of the kubeconfig user to use
+
+.PP
+\fB\-\-username\fP=""
+ Username for basic authentication to the API server.
+
+.PP
+\fB\-\-v\fP=0
+ log level for V logs
+
+.PP
+\fB\-\-vmodule\fP=
+ comma\-separated list of pattern=N settings for file\-filtered logging
+
+
+.SH EXAMPLE
+.PP
+.RS
+
+.nf
+ # If you don't already have a .dockercfg file, you can create a dockercfg secret directly by using:
+ $ kubectl create secret docker\-registry my\-secret \-\-docker\-server=DOCKER\_REGISTRY\_SERVER \-\-docker\-username=DOCKER\_USER \-\-docker\-password=DOCKER\_PASSWORD \-\-docker\-email=DOCKER\_EMAIL
+
+.fi
+.RE
+
+
+.SH SEE ALSO
+.PP
+\fBkubectl\-create\-secret(1)\fP,
+
+
+.SH HISTORY
+.PP
+January 2015, Originally compiled by Eric Paris (eparis at redhat dot com) based on the kubernetes source material, but hopefully they have been automatically generated since!
diff --git a/docs/man/man1/kubectl-create-secret-generic.1 b/docs/man/man1/kubectl-create-secret-generic.1
new file mode 100644
index 00000000000..48f7ad046c5
--- /dev/null
+++ b/docs/man/man1/kubectl-create-secret-generic.1
@@ -0,0 +1,194 @@
+.TH "KUBERNETES" "1" " kubernetes User Manuals" "Eric Paris" "Jan 2015" ""
+
+
+.SH NAME
+.PP
+kubectl create secret generic \- Create a secret from a local file, directory or literal value.
+
+
+.SH SYNOPSIS
+.PP
+\fBkubectl create secret generic\fP [OPTIONS]
+
+
+.SH DESCRIPTION
+.PP
+Create a secret based on a file, directory, or specified literal value
+
+.PP
+A single secret may package one or more key/value pairs.
+
+.PP
+When creating a secret based on a file, the key will default to the basename of the file, and the value will
+default to the file content. If the basename is an invalid key, you may specify an alternate key.
+
+.PP
+When creating a secret based on a directory, each file whose basename is a valid key in the directory will be
+packaged into the secret. Any directory entries except regular files are ignored (e.g. subdirectories,
+symlinks, devices, pipes, etc).
+
+
+.SH OPTIONS
+.PP
+\fB\-\-dry\-run\fP=false
+ If true, only print the object that would be sent, without sending it.
+
+.PP
+\fB\-\-from\-file\fP=[]
+ Key files can be specified using their file path, in which case a default name will be given to them, or optionally with a name and file path, in which case the given name will be used. Specifying a directory will iterate each named file in the directory that is a valid secret key.
+
+.PP
+\fB\-\-from\-literal\fP=[]
+ Specify a key and literal value to insert in secret (i.e. mykey=somevalue)
+
+.PP
+\fB\-\-generator\fP="secret/v1"
+ The name of the API generator to use.
+
+.PP
+\fB\-o\fP, \fB\-\-output\fP=""
+ Output format. One of: json|yaml|wide|name|go\-template=...|go\-template\-file=...|jsonpath=...|jsonpath\-file=... See golang template [
+\[la]http://golang.org/pkg/text/template/#pkg-overview\[ra]] and jsonpath template [
+\[la]http://releases.k8s.io/HEAD/docs/user-guide/jsonpath.md\[ra]].
+
+.PP
+\fB\-\-output\-version\fP=""
+ Output the formatted object with the given version (default api\-version).
+
+.PP
+\fB\-\-save\-config\fP=false
+ If true, the configuration of current object will be saved in its annotation. This is useful when you want to perform kubectl apply on this object in the future.
+
+.PP
+\fB\-\-schema\-cache\-dir\fP="\~/.kube/schema"
+ If non\-empty, load/store cached API schemas in this directory, default is '$HOME/.kube/schema'
+
+.PP
+\fB\-\-type\fP=""
+ The type of secret to create
+
+.PP
+\fB\-\-validate\fP=true
+ If true, use a schema to validate the input before sending it
+
+
+.SH OPTIONS INHERITED FROM PARENT COMMANDS
+.PP
+\fB\-\-alsologtostderr\fP=false
+ log to standard error as well as files
+
+.PP
+\fB\-\-api\-version\fP=""
+ The API version to use when talking to the server
+
+.PP
+\fB\-\-certificate\-authority\fP=""
+ Path to a cert. file for the certificate authority.
+
+.PP
+\fB\-\-client\-certificate\fP=""
+ Path to a client certificate file for TLS.
+
+.PP
+\fB\-\-client\-key\fP=""
+ Path to a client key file for TLS.
+
+.PP
+\fB\-\-cluster\fP=""
+ The name of the kubeconfig cluster to use
+
+.PP
+\fB\-\-context\fP=""
+ The name of the kubeconfig context to use
+
+.PP
+\fB\-\-insecure\-skip\-tls\-verify\fP=false
+ If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.
+
+.PP
+\fB\-\-kubeconfig\fP=""
+ Path to the kubeconfig file to use for CLI requests.
+
+.PP
+\fB\-\-log\-backtrace\-at\fP=:0
+ when logging hits line file:N, emit a stack trace
+
+.PP
+\fB\-\-log\-dir\fP=""
+ If non\-empty, write log files in this directory
+
+.PP
+\fB\-\-log\-flush\-frequency\fP=5s
+ Maximum number of seconds between log flushes
+
+.PP
+\fB\-\-logtostderr\fP=true
+ log to standard error instead of files
+
+.PP
+\fB\-\-match\-server\-version\fP=false
+ Require server version to match client version
+
+.PP
+\fB\-\-namespace\fP=""
+ If present, the namespace scope for this CLI request.
+
+.PP
+\fB\-\-password\fP=""
+ Password for basic authentication to the API server.
+
+.PP
+\fB\-s\fP, \fB\-\-server\fP=""
+ The address and port of the Kubernetes API server
+
+.PP
+\fB\-\-stderrthreshold\fP=2
+ logs at or above this threshold go to stderr
+
+.PP
+\fB\-\-token\fP=""
+ Bearer token for authentication to the API server.
+
+.PP
+\fB\-\-user\fP=""
+ The name of the kubeconfig user to use
+
+.PP
+\fB\-\-username\fP=""
+ Username for basic authentication to the API server.
+
+.PP
+\fB\-\-v\fP=0
+ log level for V logs
+
+.PP
+\fB\-\-vmodule\fP=
+ comma\-separated list of pattern=N settings for file\-filtered logging
+
+
+.SH EXAMPLE
+.PP
+.RS
+
+.nf
+ # Create a new secret named my\-secret with keys for each file in folder bar
+ $ kubectl create secret generic my\-secret \-\-from\-file=path/to/bar
+
+ # Create a new secret named my\-secret with specified keys instead of names on disk
+ $ kubectl create secret generic my\-secret \-\-from\-file=ssh\-privatekey=\~/.ssh/id\_rsa \-\-from\-file=ssh\-publickey=\~/.ssh/id\_rsa.pub
+
+ # Create a new secret named my\-secret with key1=supersecret and key2=topsecret
+ $ kubectl create secret generic my\-secret \-\-from\-literal=key1=supersecret \-\-from\-literal=key2=topsecret
+
+.fi
+.RE
+
+
+.SH SEE ALSO
+.PP
+\fBkubectl\-create\-secret(1)\fP,
+
+
+.SH HISTORY
+.PP
+January 2015, Originally compiled by Eric Paris (eparis at redhat dot com) based on the kubernetes source material, but hopefully they have been automatically generated since!
diff --git a/docs/man/man1/kubectl-create-secret.1 b/docs/man/man1/kubectl-create-secret.1
new file mode 100644
index 00000000000..9cf76d40899
--- /dev/null
+++ b/docs/man/man1/kubectl-create-secret.1
@@ -0,0 +1,120 @@
+.TH "KUBERNETES" "1" " kubernetes User Manuals" "Eric Paris" "Jan 2015" ""
+
+
+.SH NAME
+.PP
+kubectl create secret \- Create a secret using specified subcommand.
+
+
+.SH SYNOPSIS
+.PP
+\fBkubectl create secret\fP [OPTIONS]
+
+
+.SH DESCRIPTION
+.PP
+Create a secret using specified subcommand.
+
+
+.SH OPTIONS INHERITED FROM PARENT COMMANDS
+.PP
+\fB\-\-alsologtostderr\fP=false
+ log to standard error as well as files
+
+.PP
+\fB\-\-api\-version\fP=""
+ The API version to use when talking to the server
+
+.PP
+\fB\-\-certificate\-authority\fP=""
+ Path to a cert. file for the certificate authority.
+
+.PP
+\fB\-\-client\-certificate\fP=""
+ Path to a client certificate file for TLS.
+
+.PP
+\fB\-\-client\-key\fP=""
+ Path to a client key file for TLS.
+
+.PP
+\fB\-\-cluster\fP=""
+ The name of the kubeconfig cluster to use
+
+.PP
+\fB\-\-context\fP=""
+ The name of the kubeconfig context to use
+
+.PP
+\fB\-\-insecure\-skip\-tls\-verify\fP=false
+ If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.
+
+.PP
+\fB\-\-kubeconfig\fP=""
+ Path to the kubeconfig file to use for CLI requests.
+
+.PP
+\fB\-\-log\-backtrace\-at\fP=:0
+ when logging hits line file:N, emit a stack trace
+
+.PP
+\fB\-\-log\-dir\fP=""
+ If non\-empty, write log files in this directory
+
+.PP
+\fB\-\-log\-flush\-frequency\fP=5s
+ Maximum number of seconds between log flushes
+
+.PP
+\fB\-\-logtostderr\fP=true
+ log to standard error instead of files
+
+.PP
+\fB\-\-match\-server\-version\fP=false
+ Require server version to match client version
+
+.PP
+\fB\-\-namespace\fP=""
+ If present, the namespace scope for this CLI request.
+
+.PP
+\fB\-\-password\fP=""
+ Password for basic authentication to the API server.
+
+.PP
+\fB\-s\fP, \fB\-\-server\fP=""
+ The address and port of the Kubernetes API server
+
+.PP
+\fB\-\-stderrthreshold\fP=2
+ logs at or above this threshold go to stderr
+
+.PP
+\fB\-\-token\fP=""
+ Bearer token for authentication to the API server.
+
+.PP
+\fB\-\-user\fP=""
+ The name of the kubeconfig user to use
+
+.PP
+\fB\-\-username\fP=""
+ Username for basic authentication to the API server.
+
+.PP
+\fB\-\-v\fP=0
+ log level for V logs
+
+.PP
+\fB\-\-vmodule\fP=
+ comma\-separated list of pattern=N settings for file\-filtered logging
+
+
+.SH SEE ALSO
+.PP
+\fBkubectl\-create(1)\fP, \fBkubectl\-create\-secret\-docker\-registry(1)\fP, \fBkubectl\-create\-secret\-generic(1)\fP,
+
+
+.SH HISTORY
+.PP
+January 2015, Originally compiled by Eric Paris (eparis at redhat dot com) based on the kubernetes source material, but hopefully they have been automatically generated since!
diff --git a/docs/man/man1/kubectl-create.1 b/docs/man/man1/kubectl-create.1
index 5a0fdccaad6..e10b7828558 100644
--- a/docs/man/man1/kubectl-create.1
+++ b/docs/man/man1/kubectl-create.1
@@ -152,7 +152,7 @@ $ cat pod.json | kubectl create \-f \-
.SH SEE ALSO
.PP
-\fBkubectl(1)\fP,
+\fBkubectl(1)\fP, \fBkubectl\-create\-namespace(1)\fP, \fBkubectl\-create\-secret(1)\fP,
.SH HISTORY
diff --git a/docs/user-guide/kubectl/kubectl_create.md b/docs/user-guide/kubectl/kubectl_create.md
index 111ef699058..83a49e5a886 100644
--- a/docs/user-guide/kubectl/kubectl_create.md
+++ b/docs/user-guide/kubectl/kubectl_create.md
@@ -97,6 +97,8 @@ $ cat pod.json | kubectl create -f -
### SEE ALSO
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
+* [kubectl create namespace](kubectl_create_namespace.md) - Create a namespace with the specified name.
+* [kubectl create secret](kubectl_create_secret.md) - Create a secret using specified subcommand.
###### Auto generated by spf13/cobra on 24-Nov-2015
diff --git a/docs/user-guide/kubectl/kubectl_create_namespace.md b/docs/user-guide/kubectl/kubectl_create_namespace.md
new file mode 100644
index 00000000000..64be9a00462
--- /dev/null
+++ b/docs/user-guide/kubectl/kubectl_create_namespace.md
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+
+
PLEASE NOTE: This document applies to the HEAD of the source tree
+
+If you are using a released version of Kubernetes, you should
+refer to the docs that go with that version.
+
+
+The latest release of this document can be found
+[here](http://releases.k8s.io/release-1.1/docs/user-guide/kubectl/kubectl_create_namespace.md).
+
+Documentation for other releases can be found at
+[releases.k8s.io](http://releases.k8s.io).
+
+--
+
+
+
+
+
+## kubectl create namespace
+
+Create a namespace with the specified name.
+
+### Synopsis
+
+
+
+Create a namespace with the specified name.
+
+```
+kubectl create namespace NAME [--dry-run]
+```
+
+### Examples
+
+```
+ # Create a new namespace named my-namespace
+ $ kubectl create namespace my-namespace
+```
+
+### Options
+
+```
+ --dry-run[=false]: If true, only print the object that would be sent, without sending it.
+ --generator="namespace/v1": The name of the API generator to use.
+ -o, --output="": Output format. One of: json|yaml|wide|name|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=... See golang template [http://golang.org/pkg/text/template/#pkg-overview] and jsonpath template [http://releases.k8s.io/HEAD/docs/user-guide/jsonpath.md].
+ --output-version="": Output the formatted object with the given version (default api-version).
+ --save-config[=false]: If true, the configuration of current object will be saved in its annotation. This is useful when you want to perform kubectl apply on this object in the future.
+ --schema-cache-dir="~/.kube/schema": If non-empty, load/store cached API schemas in this directory, default is '$HOME/.kube/schema'
+ --validate[=true]: If true, use a schema to validate the input before sending it
+```
+
+### Options inherited from parent commands
+
+```
+ --alsologtostderr[=false]: log to standard error as well as files
+ --api-version="": The API version to use when talking to the server
+ --certificate-authority="": Path to a cert. file for the certificate authority.
+ --client-certificate="": Path to a client certificate file for TLS.
+ --client-key="": Path to a client key file for TLS.
+ --cluster="": The name of the kubeconfig cluster to use
+ --context="": The name of the kubeconfig context to use
+ --insecure-skip-tls-verify[=false]: If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.
+ --kubeconfig="": Path to the kubeconfig file to use for CLI requests.
+ --log-backtrace-at=:0: when logging hits line file:N, emit a stack trace
+ --log-dir="": If non-empty, write log files in this directory
+ --log-flush-frequency=5s: Maximum number of seconds between log flushes
+ --logtostderr[=true]: log to standard error instead of files
+ --match-server-version[=false]: Require server version to match client version
+ --namespace="": If present, the namespace scope for this CLI request.
+ --password="": Password for basic authentication to the API server.
+ -s, --server="": The address and port of the Kubernetes API server
+ --stderrthreshold=2: logs at or above this threshold go to stderr
+ --token="": Bearer token for authentication to the API server.
+ --user="": The name of the kubeconfig user to use
+ --username="": Username for basic authentication to the API server.
+ --v=0: log level for V logs
+ --vmodule=: comma-separated list of pattern=N settings for file-filtered logging
+```
+
+### SEE ALSO
+
+* [kubectl create](kubectl_create.md) - Create a resource by filename or stdin
+
+###### Auto generated by spf13/cobra on 14-Dec-2015
+
+
+[]()
+
diff --git a/docs/user-guide/kubectl/kubectl_create_secret.md b/docs/user-guide/kubectl/kubectl_create_secret.md
new file mode 100644
index 00000000000..289b1feb76b
--- /dev/null
+++ b/docs/user-guide/kubectl/kubectl_create_secret.md
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+PLEASE NOTE: This document applies to the HEAD of the source tree
+
+If you are using a released version of Kubernetes, you should
+refer to the docs that go with that version.
+
+
+The latest release of this document can be found
+[here](http://releases.k8s.io/release-1.1/docs/user-guide/kubectl/kubectl_create_secret.md).
+
+Documentation for other releases can be found at
+[releases.k8s.io](http://releases.k8s.io).
+
+--
+
+
+
+
+
+## kubectl create secret
+
+Create a secret using specified subcommand.
+
+### Synopsis
+
+
+Create a secret using specified subcommand.
+
+```
+kubectl create secret
+```
+
+### Options inherited from parent commands
+
+```
+ --alsologtostderr[=false]: log to standard error as well as files
+ --api-version="": The API version to use when talking to the server
+ --certificate-authority="": Path to a cert. file for the certificate authority.
+ --client-certificate="": Path to a client certificate file for TLS.
+ --client-key="": Path to a client key file for TLS.
+ --cluster="": The name of the kubeconfig cluster to use
+ --context="": The name of the kubeconfig context to use
+ --insecure-skip-tls-verify[=false]: If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.
+ --kubeconfig="": Path to the kubeconfig file to use for CLI requests.
+ --log-backtrace-at=:0: when logging hits line file:N, emit a stack trace
+ --log-dir="": If non-empty, write log files in this directory
+ --log-flush-frequency=5s: Maximum number of seconds between log flushes
+ --logtostderr[=true]: log to standard error instead of files
+ --match-server-version[=false]: Require server version to match client version
+ --namespace="": If present, the namespace scope for this CLI request.
+ --password="": Password for basic authentication to the API server.
+ -s, --server="": The address and port of the Kubernetes API server
+ --stderrthreshold=2: logs at or above this threshold go to stderr
+ --token="": Bearer token for authentication to the API server.
+ --user="": The name of the kubeconfig user to use
+ --username="": Username for basic authentication to the API server.
+ --v=0: log level for V logs
+ --vmodule=: comma-separated list of pattern=N settings for file-filtered logging
+```
+
+### SEE ALSO
+
+* [kubectl create](kubectl_create.md) - Create a resource by filename or stdin
+* [kubectl create secret docker-registry](kubectl_create_secret_docker-registry.md) - Create a secret for use with a Docker registry.
+* [kubectl create secret generic](kubectl_create_secret_generic.md) - Create a secret from a local file, directory or literal value.
+
+###### Auto generated by spf13/cobra on 14-Dec-2015
+
+
+[]()
+
diff --git a/docs/user-guide/kubectl/kubectl_create_secret_docker-registry.md b/docs/user-guide/kubectl/kubectl_create_secret_docker-registry.md
new file mode 100644
index 00000000000..e2fa456fada
--- /dev/null
+++ b/docs/user-guide/kubectl/kubectl_create_secret_docker-registry.md
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+
+
+
+PLEASE NOTE: This document applies to the HEAD of the source tree
+
+If you are using a released version of Kubernetes, you should
+refer to the docs that go with that version.
+
+
+The latest release of this document can be found
+[here](http://releases.k8s.io/release-1.1/docs/user-guide/kubectl/kubectl_create_secret_docker-registry.md).
+
+Documentation for other releases can be found at
+[releases.k8s.io](http://releases.k8s.io).
+
+--
+
+
+
+
+
+## kubectl create secret docker-registry
+
+Create a secret for use with a Docker registry.
+
+### Synopsis
+
+
+
+Create a new secret for use with Docker registries.
+
+Dockercfg secrets are used to authenticate against Docker registries.
+
+When using the Docker command line to push images, you can authenticate to a given registry by running
+ 'docker login DOCKER_REGISTRY_SERVER --username=DOCKER_USER --password=DOCKER_PASSWORD --email=DOCKER_EMAIL'.
+That produces a ~/.dockercfg file that is used by subsequent 'docker push' and 'docker pull' commands to
+authenticate to the registry.
+
+When creating applications, you may have a Docker registry that requires authentication. In order for the
+nodes to pull images on your behalf, they have to have the credentials. You can provide this information
+by creating a dockercfg secret and attaching it to your service account.
+
+```
+kubectl create secret docker-registry NAME --docker-username=user --docker-password=password --docker-email=email [--docker-server=string] [--from-literal=key1=value1] [--dry-run]
+```
+
+### Examples
+
+```
+ # If you don't already have a .dockercfg file, you can create a dockercfg secret directly by using:
+ $ kubectl create secret docker-registry my-secret --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL
+```
+
+### Options
+
+```
+ --docker-email="": Email for Docker registry
+ --docker-password="": Password for Docker registry authentication
+ --docker-server="https://index.docker.io/v1/": Server location for Docker registry
+ --docker-username="": Username for Docker registry authentication
+ --dry-run[=false]: If true, only print the object that would be sent, without sending it.
+ --generator="secret-for-docker-registry/v1": The name of the API generator to use.
+ -o, --output="": Output format. One of: json|yaml|wide|name|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=... See golang template [http://golang.org/pkg/text/template/#pkg-overview] and jsonpath template [http://releases.k8s.io/HEAD/docs/user-guide/jsonpath.md].
+ --output-version="": Output the formatted object with the given version (default api-version).
+ --save-config[=false]: If true, the configuration of current object will be saved in its annotation. This is useful when you want to perform kubectl apply on this object in the future.
+ --schema-cache-dir="~/.kube/schema": If non-empty, load/store cached API schemas in this directory, default is '$HOME/.kube/schema'
+ --validate[=true]: If true, use a schema to validate the input before sending it
+```
+
+### Options inherited from parent commands
+
+```
+ --alsologtostderr[=false]: log to standard error as well as files
+ --api-version="": The API version to use when talking to the server
+ --certificate-authority="": Path to a cert. file for the certificate authority.
+ --client-certificate="": Path to a client certificate file for TLS.
+ --client-key="": Path to a client key file for TLS.
+ --cluster="": The name of the kubeconfig cluster to use
+ --context="": The name of the kubeconfig context to use
+ --insecure-skip-tls-verify[=false]: If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.
+ --kubeconfig="": Path to the kubeconfig file to use for CLI requests.
+ --log-backtrace-at=:0: when logging hits line file:N, emit a stack trace
+ --log-dir="": If non-empty, write log files in this directory
+ --log-flush-frequency=5s: Maximum number of seconds between log flushes
+ --logtostderr[=true]: log to standard error instead of files
+ --match-server-version[=false]: Require server version to match client version
+ --namespace="": If present, the namespace scope for this CLI request.
+ --password="": Password for basic authentication to the API server.
+ -s, --server="": The address and port of the Kubernetes API server
+ --stderrthreshold=2: logs at or above this threshold go to stderr
+ --token="": Bearer token for authentication to the API server.
+ --user="": The name of the kubeconfig user to use
+ --username="": Username for basic authentication to the API server.
+ --v=0: log level for V logs
+ --vmodule=: comma-separated list of pattern=N settings for file-filtered logging
+```
+
+### SEE ALSO
+
+* [kubectl create secret](kubectl_create_secret.md) - Create a secret using specified subcommand.
+
+###### Auto generated by spf13/cobra on 14-Dec-2015
+
+
+[]()
+
diff --git a/docs/user-guide/kubectl/kubectl_create_secret_generic.md b/docs/user-guide/kubectl/kubectl_create_secret_generic.md
new file mode 100644
index 00000000000..1b9de84f029
--- /dev/null
+++ b/docs/user-guide/kubectl/kubectl_create_secret_generic.md
@@ -0,0 +1,122 @@
+
+
+
+
+
+
+
+
+
+
+PLEASE NOTE: This document applies to the HEAD of the source tree
+
+If you are using a released version of Kubernetes, you should
+refer to the docs that go with that version.
+
+
+The latest release of this document can be found
+[here](http://releases.k8s.io/release-1.1/docs/user-guide/kubectl/kubectl_create_secret_generic.md).
+
+Documentation for other releases can be found at
+[releases.k8s.io](http://releases.k8s.io).
+
+--
+
+
+
+
+
+## kubectl create secret generic
+
+Create a secret from a local file, directory or literal value.
+
+### Synopsis
+
+
+
+Create a secret based on a file, directory, or specified literal value
+
+A single secret may package one or more key/value pairs.
+
+When creating a secret based on a file, the key will default to the basename of the file, and the value will
+default to the file content. If the basename is an invalid key, you may specify an alternate key.
+
+When creating a secret based on a directory, each file whose basename is a valid key in the directory will be
+packaged into the secret. Any directory entries except regular files are ignored (e.g. subdirectories,
+symlinks, devices, pipes, etc).
+
+
+```
+kubectl create secret generic NAME [--type=string] [--from-file=[key=]source] [--from-literal=key1=value1] [--dry-run]
+```
+
+### Examples
+
+```
+ # Create a new secret named my-secret with keys for each file in folder bar
+ $ kubectl create secret generic my-secret --from-file=path/to/bar
+
+ # Create a new secret named my-secret with specified keys instead of names on disk
+ $ kubectl create secret generic my-secret --from-file=ssh-privatekey=~/.ssh/id_rsa --from-file=ssh-publickey=~/.ssh/id_rsa.pub
+
+ # Create a new secret named my-secret with key1=supersecret and key2=topsecret
+ $ kubectl create secret generic my-secret --from-literal=key1=supersecret --from-literal=key2=topsecret
+```
+
+### Options
+
+```
+ --dry-run[=false]: If true, only print the object that would be sent, without sending it.
+ --from-file=[]: Key files can be specified using their file path, in which case a default name will be given to them, or optionally with a name and file path, in which case the given name will be used. Specifying a directory will iterate each named file in the directory that is a valid secret key.
+ --from-literal=[]: Specify a key and literal value to insert in secret (i.e. mykey=somevalue)
+ --generator="secret/v1": The name of the API generator to use.
+ -o, --output="": Output format. One of: json|yaml|wide|name|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=... See golang template [http://golang.org/pkg/text/template/#pkg-overview] and jsonpath template [http://releases.k8s.io/HEAD/docs/user-guide/jsonpath.md].
+ --output-version="": Output the formatted object with the given version (default api-version).
+ --save-config[=false]: If true, the configuration of current object will be saved in its annotation. This is useful when you want to perform kubectl apply on this object in the future.
+ --schema-cache-dir="~/.kube/schema": If non-empty, load/store cached API schemas in this directory, default is '$HOME/.kube/schema'
+ --type="": The type of secret to create
+ --validate[=true]: If true, use a schema to validate the input before sending it
+```
+
+### Options inherited from parent commands
+
+```
+ --alsologtostderr[=false]: log to standard error as well as files
+ --api-version="": The API version to use when talking to the server
+ --certificate-authority="": Path to a cert. file for the certificate authority.
+ --client-certificate="": Path to a client certificate file for TLS.
+ --client-key="": Path to a client key file for TLS.
+ --cluster="": The name of the kubeconfig cluster to use
+ --context="": The name of the kubeconfig context to use
+ --insecure-skip-tls-verify[=false]: If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.
+ --kubeconfig="": Path to the kubeconfig file to use for CLI requests.
+ --log-backtrace-at=:0: when logging hits line file:N, emit a stack trace
+ --log-dir="": If non-empty, write log files in this directory
+ --log-flush-frequency=5s: Maximum number of seconds between log flushes
+ --logtostderr[=true]: log to standard error instead of files
+ --match-server-version[=false]: Require server version to match client version
+ --namespace="": If present, the namespace scope for this CLI request.
+ --password="": Password for basic authentication to the API server.
+ -s, --server="": The address and port of the Kubernetes API server
+ --stderrthreshold=2: logs at or above this threshold go to stderr
+ --token="": Bearer token for authentication to the API server.
+ --user="": The name of the kubeconfig user to use
+ --username="": Username for basic authentication to the API server.
+ --v=0: log level for V logs
+ --vmodule=: comma-separated list of pattern=N settings for file-filtered logging
+```
+
+### SEE ALSO
+
+* [kubectl create secret](kubectl_create_secret.md) - Create a secret using specified subcommand.
+
+###### Auto generated by spf13/cobra on 14-Dec-2015
+
+
+[]()
+
diff --git a/hack/test-cmd.sh b/hack/test-cmd.sh
index 7d8ec3cfea6..1a6ba00d75b 100755
--- a/hack/test-cmd.sh
+++ b/hack/test-cmd.sh
@@ -224,6 +224,8 @@ runTests() {
hpa_cpu_field=".spec.cpuUtilization.targetPercentage"
job_parallelism_field=".spec.parallelism"
deployment_replicas=".spec.replicas"
+ secret_data=".data"
+ secret_type=".type"
# Passing no arguments to create is an error
! kubectl create
@@ -674,6 +676,20 @@ runTests() {
# Namespaces #
##############
+ ### Create a new namespace
+ # Pre-condition: only the "default" namespace exists
+ kube::test::get_object_assert 'namespaces' "{{range.items}}{{$id_field}}:{{end}}" 'default:'
+ # Command
+ kubectl create namespace my-namespace
+ # Post-condition: namespace 'my-namespace' is created.
+ kube::test::get_object_assert 'namespaces/my-namespace' "{{$id_field}}" 'my-namespace'
+ # Clean up
+ kubectl delete namespace my-namespace
+
+ ##############
+ # Pods in Namespaces #
+ ##############
+
### Create POD valid-pod in specific namespace
# Pre-condition: no POD is running
kube::test::get_object_assert 'pods --namespace=other' "{{range.items}}{{$id_field}}:{{end}}" ''
@@ -690,6 +706,33 @@ runTests() {
# Post-condition: no POD is running
kube::test::get_object_assert 'pods --namespace=other' "{{range.items}}{{$id_field}}:{{end}}" ''
+ ##############
+ # Secrets #
+ ##############
+
+ ### Create a generic secret in a specific namespace
+ # Pre-condition: no SECRET exists
+ kube::test::get_object_assert 'secrets --namespace=test-secrets' "{{range.items}}{{$id_field}}:{{end}}" ''
+ # Command
+ kubectl create secret generic test-secret --from-literal=key1=value1 --type=test-type --namespace=test-secrets
+ # Post-condition: secret exists and has expected values
+ kube::test::get_object_assert 'secret/test-secret --namespace=test-secrets' "{{$id_field}}" 'test-secret'
+ kube::test::get_object_assert 'secret/test-secret --namespace=test-secrets' "{{$secret_type}}" 'test-type'
+ [[ "$(kubectl get secret/test-secret --namespace=test-secrets -o yaml "${kube_flags[@]}" | grep 'key1: dmFsdWUx')" ]]
+ # Clean-up
+ kubectl delete secret test-secret --namespace=test-secrets
+
+ ### Create a docker-registry secret in a specific namespace
+ # Pre-condition: no SECRET exists
+ kube::test::get_object_assert 'secrets --namespace=test-secrets' "{{range.items}}{{$id_field}}:{{end}}" ''
+ # Command
+ kubectl create secret docker-registry test-secret --docker-username=test-user --docker-password=test-password --docker-email='test-user@test.com' --namespace=test-secrets
+ # Post-condition: secret exists and has expected values
+ kube::test::get_object_assert 'secret/test-secret --namespace=test-secrets' "{{$id_field}}" 'test-secret'
+ kube::test::get_object_assert 'secret/test-secret --namespace=test-secrets' "{{$secret_type}}" 'kubernetes.io/dockercfg'
+ [[ "$(kubectl get secret/test-secret --namespace=test-secrets -o yaml "${kube_flags[@]}" | grep '.dockercfg:')" ]]
+ # Clean-up
+ kubectl delete secret test-secret --namespace=test-secrets
#################
# Pod templates #
diff --git a/hack/verify-flags/known-flags.txt b/hack/verify-flags/known-flags.txt
index cefee443fa1..1f047f5c92a 100644
--- a/hack/verify-flags/known-flags.txt
+++ b/hack/verify-flags/known-flags.txt
@@ -70,8 +70,12 @@ dest-file
disable-filter
dockercfg-path
docker-endpoint
+docker-email
docker-exec-handler
+docker-password
driver-port
+docker-server
+docker-username
dry-run
duration-sec
e2e-output-dir
@@ -101,6 +105,8 @@ file-suffix
forward-services
framework-name
framework-weburi
+from-file
+from-literal
func-dest
fuzz-iters
gather-logs-sizes
diff --git a/pkg/kubectl/cmd/cmd_test.go b/pkg/kubectl/cmd/cmd_test.go
index f18ea94ffad..50f43e48fbf 100644
--- a/pkg/kubectl/cmd/cmd_test.go
+++ b/pkg/kubectl/cmd/cmd_test.go
@@ -200,13 +200,8 @@ func NewAPIFactory() (*cmdutil.Factory, *testFactory, runtime.Codec) {
t := &testFactory{
Validator: validation.NullSchema{},
}
- generators := map[string]kubectl.Generator{
- "run/v1": kubectl.BasicReplicationController{},
- "run-pod/v1": kubectl.BasicPod{},
- "service/v1": kubectl.ServiceGeneratorV1{},
- "service/v2": kubectl.ServiceGeneratorV2{},
- "service/test": testServiceGenerator{},
- }
+ generators := cmdutil.DefaultGenerators()
+ generators["service/test"] = testServiceGenerator{}
f := &cmdutil.Factory{
Object: func() (meta.RESTMapper, runtime.ObjectTyper) {
return testapi.Default.RESTMapper(), api.Scheme
diff --git a/pkg/kubectl/cmd/create.go b/pkg/kubectl/cmd/create.go
index 483ba70fedd..6b887a07627 100644
--- a/pkg/kubectl/cmd/create.go
+++ b/pkg/kubectl/cmd/create.go
@@ -24,6 +24,7 @@ import (
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/api"
+ "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/kubectl"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource"
@@ -56,6 +57,10 @@ func NewCmdCreate(f *cmdutil.Factory, out io.Writer) *cobra.Command {
Long: create_long,
Example: create_example,
Run: func(cmd *cobra.Command, args []string) {
+ if len(options.Filenames) == 0 {
+ cmd.Help()
+ return
+ }
cmdutil.CheckErr(ValidateArgs(cmd, args))
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
cmdutil.CheckErr(RunCreate(f, cmd, out, options))
@@ -68,6 +73,10 @@ func NewCmdCreate(f *cmdutil.Factory, out io.Writer) *cobra.Command {
cmdutil.AddValidateFlags(cmd)
cmdutil.AddOutputFlagsForMutation(cmd)
cmdutil.AddApplyAnnotationFlags(cmd)
+
+ // create subcommands
+ cmd.AddCommand(NewCmdCreateNamespace(f, out))
+ cmd.AddCommand(NewCmdCreateSecret(f, out))
return cmd
}
@@ -172,3 +181,66 @@ func createAndRefresh(info *resource.Info) error {
info.Refresh(obj, true)
return nil
}
+
+// NameFromCommandArgs is a utility function for commands that assume the first argument is a resource name
+func NameFromCommandArgs(cmd *cobra.Command, args []string) (string, error) {
+ if len(args) == 0 {
+ return "", cmdutil.UsageError(cmd, "NAME is required")
+ }
+ return args[0], nil
+}
+
+// CreateSubcommandOptions is an options struct to support create subcommands
+type CreateSubcommandOptions struct {
+ // Name of resource being created
+ Name string
+ // StructuredGenerator is the resource generator for the object being created
+ StructuredGenerator kubectl.StructuredGenerator
+ // DryRun is true if the command should be simulated but not run against the server
+ DryRun bool
+ // OutputFormat
+ OutputFormat string
+}
+
+// RunCreateSubcommand executes a create subcommand using the specified options
+func RunCreateSubcommand(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *CreateSubcommandOptions) error {
+ namespace, _, err := f.DefaultNamespace()
+ if err != nil {
+ return err
+ }
+ obj, err := options.StructuredGenerator.StructuredGenerate()
+ if err != nil {
+ return err
+ }
+ mapper, typer := f.Object()
+ gvk, err := typer.ObjectKind(obj)
+ mapping, err := mapper.RESTMapping(unversioned.GroupKind{Group: gvk.Group, Kind: gvk.Kind}, gvk.Version)
+ if err != nil {
+ return err
+ }
+ client, err := f.RESTClient(mapping)
+ if err != nil {
+ return err
+ }
+ resourceMapper := &resource.Mapper{ObjectTyper: typer, RESTMapper: mapper, ClientMapper: f.ClientMapperForCommand()}
+ info, err := resourceMapper.InfoForObject(obj)
+ if err != nil {
+ return err
+ }
+ if err := kubectl.UpdateApplyAnnotation(info); err != nil {
+ return err
+ }
+ if !options.DryRun {
+ obj, err = resource.NewHelper(client, mapping).Create(namespace, false, info.Object)
+ if err != nil {
+ return err
+ }
+ }
+
+ if useShortOutput := options.OutputFormat == "name"; useShortOutput || len(options.OutputFormat) == 0 {
+ cmdutil.PrintSuccess(mapper, useShortOutput, out, mapping.Resource, options.Name, "created")
+ return nil
+ }
+
+ return f.PrintObject(cmd, obj, out)
+}
diff --git a/pkg/kubectl/cmd/create_namespace.go b/pkg/kubectl/cmd/create_namespace.go
new file mode 100644
index 00000000000..f9e5c888539
--- /dev/null
+++ b/pkg/kubectl/cmd/create_namespace.go
@@ -0,0 +1,75 @@
+/*
+Copyright 2015 The Kubernetes Authors All rights reserved.
+
+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 cmd
+
+import (
+ "fmt"
+ "io"
+
+ "github.com/spf13/cobra"
+
+ "k8s.io/kubernetes/pkg/kubectl"
+ cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
+)
+
+const (
+ namespaceLong = `
+Create a namespace with the specified name.`
+
+ namespaceExample = ` # Create a new namespace named my-namespace
+ $ kubectl create namespace my-namespace`
+)
+
+// NewCmdCreateNamespace is a macro command to create a new namespace
+func NewCmdCreateNamespace(f *cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "namespace NAME [--dry-run]",
+ Aliases: []string{"ns"},
+ Short: "Create a namespace with the specified name.",
+ Long: namespaceLong,
+ Example: namespaceExample,
+ Run: func(cmd *cobra.Command, args []string) {
+ err := CreateNamespace(f, cmdOut, cmd, args)
+ cmdutil.CheckErr(err)
+ },
+ }
+ cmdutil.AddApplyAnnotationFlags(cmd)
+ cmdutil.AddValidateFlags(cmd)
+ cmdutil.AddGeneratorFlags(cmd, cmdutil.NamespaceV1GeneratorName)
+ return cmd
+}
+
+// CreateNamespace implements the behavior to run the create namespace command
+func CreateNamespace(f *cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
+ name, err := NameFromCommandArgs(cmd, args)
+ if err != nil {
+ return err
+ }
+ var generator kubectl.StructuredGenerator
+ switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
+ case cmdutil.NamespaceV1GeneratorName:
+ generator = &kubectl.NamespaceGeneratorV1{Name: name}
+ default:
+ return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not supported.", generatorName))
+ }
+ return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
+ Name: name,
+ StructuredGenerator: generator,
+ DryRun: cmdutil.GetFlagBool(cmd, "dry-run"),
+ OutputFormat: cmdutil.GetFlagString(cmd, "output"),
+ })
+}
diff --git a/pkg/kubectl/cmd/create_namespace_test.go b/pkg/kubectl/cmd/create_namespace_test.go
new file mode 100644
index 00000000000..dd74eec4bd2
--- /dev/null
+++ b/pkg/kubectl/cmd/create_namespace_test.go
@@ -0,0 +1,53 @@
+/*
+Copyright 2014 The Kubernetes Authors All rights reserved.
+
+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 cmd
+
+import (
+ "bytes"
+ "net/http"
+ "testing"
+
+ "k8s.io/kubernetes/pkg/api"
+ "k8s.io/kubernetes/pkg/client/unversioned/fake"
+)
+
+func TestCreateNamespace(t *testing.T) {
+ namespaceObject := &api.Namespace{}
+ namespaceObject.Name = "my-namespace"
+ f, tf, codec := NewAPIFactory()
+ tf.Printer = &testPrinter{}
+ tf.Client = &fake.RESTClient{
+ Codec: codec,
+ Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
+ switch p, m := req.URL.Path, req.Method; {
+ case p == "/namespaces" && m == "POST":
+ return &http.Response{StatusCode: 201, Body: objBody(codec, namespaceObject)}, nil
+ default:
+ t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
+ return nil, nil
+ }
+ }),
+ }
+ buf := bytes.NewBuffer([]byte{})
+ cmd := NewCmdCreateNamespace(f, buf)
+ cmd.Flags().Set("output", "name")
+ cmd.Run(cmd, []string{namespaceObject.Name})
+ expectedOutput := "namespace/" + namespaceObject.Name + "\n"
+ if buf.String() != expectedOutput {
+ t.Errorf("expected output: %s, but got: %s", buf.String(), expectedOutput)
+ }
+}
diff --git a/pkg/kubectl/cmd/create_secret.go b/pkg/kubectl/cmd/create_secret.go
new file mode 100644
index 00000000000..e8894a276ad
--- /dev/null
+++ b/pkg/kubectl/cmd/create_secret.go
@@ -0,0 +1,190 @@
+/*
+Copyright 2015 The Kubernetes Authors All rights reserved.
+
+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 cmd
+
+import (
+ "fmt"
+ "io"
+
+ "github.com/spf13/cobra"
+
+ "k8s.io/kubernetes/pkg/kubectl"
+ cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
+)
+
+// NewCmdCreateSecret groups subcommands to create various types of secrets
+func NewCmdCreateSecret(f *cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "secret",
+ Short: "Create a secret using specified subcommand.",
+ Long: "Create a secret using specified subcommand.",
+ Run: func(cmd *cobra.Command, args []string) {
+ cmd.Help()
+ },
+ }
+ cmd.AddCommand(NewCmdCreateSecretDockerRegistry(f, cmdOut))
+ cmd.AddCommand(NewCmdCreateSecretGeneric(f, cmdOut))
+ return cmd
+}
+
+const (
+ secretLong = `
+Create a secret based on a file, directory, or specified literal value
+
+A single secret may package one or more key/value pairs.
+
+When creating a secret based on a file, the key will default to the basename of the file, and the value will
+default to the file content. If the basename is an invalid key, you may specify an alternate key.
+
+When creating a secret based on a directory, each file whose basename is a valid key in the directory will be
+packaged into the secret. Any directory entries except regular files are ignored (e.g. subdirectories,
+symlinks, devices, pipes, etc).
+`
+
+ secretExample = ` # Create a new secret named my-secret with keys for each file in folder bar
+ $ kubectl create secret generic my-secret --from-file=path/to/bar
+
+ # Create a new secret named my-secret with specified keys instead of names on disk
+ $ kubectl create secret generic my-secret --from-file=ssh-privatekey=~/.ssh/id_rsa --from-file=ssh-publickey=~/.ssh/id_rsa.pub
+
+ # Create a new secret named my-secret with key1=supersecret and key2=topsecret
+ $ kubectl create secret generic my-secret --from-literal=key1=supersecret --from-literal=key2=topsecret`
+)
+
+// NewCmdCreateSecretGeneric is a command to create generic secrets from files, directories, or literal values
+func NewCmdCreateSecretGeneric(f *cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "generic NAME [--type=string] [--from-file=[key=]source] [--from-literal=key1=value1] [--dry-run]",
+ Short: "Create a secret from a local file, directory or literal value.",
+ Long: secretLong,
+ Example: secretExample,
+ Run: func(cmd *cobra.Command, args []string) {
+ err := CreateSecretGeneric(f, cmdOut, cmd, args)
+ cmdutil.CheckErr(err)
+ },
+ }
+ cmdutil.AddApplyAnnotationFlags(cmd)
+ cmdutil.AddValidateFlags(cmd)
+ cmdutil.AddGeneratorFlags(cmd, cmdutil.SecretV1GeneratorName)
+ cmd.Flags().StringSlice("from-file", []string{}, "Key files can be specified using their file path, in which case a default name will be given to them, or optionally with a name and file path, in which case the given name will be used. Specifying a directory will iterate each named file in the directory that is a valid secret key.")
+ cmd.Flags().StringSlice("from-literal", []string{}, "Specify a key and literal value to insert in secret (i.e. mykey=somevalue)")
+ cmd.Flags().String("type", "", "The type of secret to create")
+ return cmd
+}
+
+// CreateSecretGeneric is the implementation the create secret generic command
+func CreateSecretGeneric(f *cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
+ name, err := NameFromCommandArgs(cmd, args)
+ if err != nil {
+ return err
+ }
+ var generator kubectl.StructuredGenerator
+ switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
+ case cmdutil.SecretV1GeneratorName:
+ generator = &kubectl.SecretGeneratorV1{
+ Name: name,
+ Type: cmdutil.GetFlagString(cmd, "type"),
+ FileSources: cmdutil.GetFlagStringSlice(cmd, "from-file"),
+ LiteralSources: cmdutil.GetFlagStringSlice(cmd, "from-literal"),
+ }
+ default:
+ return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not supported.", generatorName))
+ }
+ return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
+ Name: name,
+ StructuredGenerator: generator,
+ DryRun: cmdutil.GetFlagBool(cmd, "dry-run"),
+ OutputFormat: cmdutil.GetFlagString(cmd, "output"),
+ })
+}
+
+const (
+ secretForDockerRegistryLong = `
+Create a new secret for use with Docker registries.
+
+Dockercfg secrets are used to authenticate against Docker registries.
+
+When using the Docker command line to push images, you can authenticate to a given registry by running
+ 'docker login DOCKER_REGISTRY_SERVER --username=DOCKER_USER --password=DOCKER_PASSWORD --email=DOCKER_EMAIL'.
+That produces a ~/.dockercfg file that is used by subsequent 'docker push' and 'docker pull' commands to
+authenticate to the registry.
+
+When creating applications, you may have a Docker registry that requires authentication. In order for the
+nodes to pull images on your behalf, they have to have the credentials. You can provide this information
+by creating a dockercfg secret and attaching it to your service account.`
+
+ secretForDockerRegistryExample = ` # If you don't already have a .dockercfg file, you can create a dockercfg secret directly by using:
+ $ kubectl create secret docker-registry my-secret --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL`
+)
+
+// NewCmdCreateSecretDockerRegistry is a macro command for creating secrets to work with Docker registries
+func NewCmdCreateSecretDockerRegistry(f *cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "docker-registry NAME --docker-username=user --docker-password=password --docker-email=email [--docker-server=string] [--from-literal=key1=value1] [--dry-run]",
+ Short: "Create a secret for use with a Docker registry.",
+ Long: secretForDockerRegistryLong,
+ Example: secretForDockerRegistryExample,
+ Run: func(cmd *cobra.Command, args []string) {
+ err := CreateSecretDockerRegistry(f, cmdOut, cmd, args)
+ cmdutil.CheckErr(err)
+ },
+ }
+ cmdutil.AddApplyAnnotationFlags(cmd)
+ cmdutil.AddValidateFlags(cmd)
+ cmdutil.AddGeneratorFlags(cmd, cmdutil.SecretForDockerRegistryV1GeneratorName)
+ cmd.Flags().String("docker-username", "", "Username for Docker registry authentication")
+ cmd.MarkFlagRequired("docker-username")
+ cmd.Flags().String("docker-password", "", "Password for Docker registry authentication")
+ cmd.MarkFlagRequired("docker-password")
+ cmd.Flags().String("docker-email", "", "Email for Docker registry")
+ cmd.MarkFlagRequired("docker-email")
+ cmd.Flags().String("docker-server", "https://index.docker.io/v1/", "Server location for Docker registry")
+ return cmd
+}
+
+// CreateSecretDockerRegistry is the implementation of the create secret docker-registry command
+func CreateSecretDockerRegistry(f *cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error {
+ name, err := NameFromCommandArgs(cmd, args)
+ if err != nil {
+ return err
+ }
+ requiredFlags := []string{"docker-username", "docker-password", "docker-email", "docker-server"}
+ for _, requiredFlag := range requiredFlags {
+ if value := cmdutil.GetFlagString(cmd, requiredFlag); len(value) == 0 {
+ return cmdutil.UsageError(cmd, "flag %s is required", requiredFlag)
+ }
+ }
+ var generator kubectl.StructuredGenerator
+ switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName {
+ case cmdutil.SecretForDockerRegistryV1GeneratorName:
+ generator = &kubectl.SecretForDockerRegistryGeneratorV1{
+ Name: name,
+ Username: cmdutil.GetFlagString(cmd, "docker-username"),
+ Email: cmdutil.GetFlagString(cmd, "docker-email"),
+ Password: cmdutil.GetFlagString(cmd, "docker-password"),
+ Server: cmdutil.GetFlagString(cmd, "docker-server"),
+ }
+ default:
+ return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not supported.", generatorName))
+ }
+ return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{
+ Name: name,
+ StructuredGenerator: generator,
+ DryRun: cmdutil.GetFlagBool(cmd, "dry-run"),
+ OutputFormat: cmdutil.GetFlagString(cmd, "output"),
+ })
+}
diff --git a/pkg/kubectl/cmd/create_secret_test.go b/pkg/kubectl/cmd/create_secret_test.go
new file mode 100644
index 00000000000..8365513eb08
--- /dev/null
+++ b/pkg/kubectl/cmd/create_secret_test.go
@@ -0,0 +1,85 @@
+/*
+Copyright 2014 The Kubernetes Authors All rights reserved.
+
+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 cmd
+
+import (
+ "bytes"
+ "net/http"
+ "testing"
+
+ "k8s.io/kubernetes/pkg/api"
+ "k8s.io/kubernetes/pkg/client/unversioned/fake"
+)
+
+func TestCreateSecretGeneric(t *testing.T) {
+ secretObject := &api.Secret{}
+ secretObject.Name = "my-secret"
+ f, tf, codec := NewAPIFactory()
+ tf.Printer = &testPrinter{}
+ tf.Client = &fake.RESTClient{
+ Codec: codec,
+ Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
+ switch p, m := req.URL.Path, req.Method; {
+ case p == "/namespaces/test/secrets" && m == "POST":
+ return &http.Response{StatusCode: 201, Body: objBody(codec, secretObject)}, nil
+ default:
+ t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
+ return nil, nil
+ }
+ }),
+ }
+ tf.Namespace = "test"
+ buf := bytes.NewBuffer([]byte{})
+ cmd := NewCmdCreateSecretGeneric(f, buf)
+ cmd.Flags().Set("output", "name")
+ cmd.Run(cmd, []string{secretObject.Name})
+ expectedOutput := "secret/" + secretObject.Name + "\n"
+ if buf.String() != expectedOutput {
+ t.Errorf("expected output: %s, but got: %s", buf.String(), expectedOutput)
+ }
+}
+
+func TestCreateSecretDockerRegistry(t *testing.T) {
+ secretObject := &api.Secret{}
+ secretObject.Name = "my-secret"
+ f, tf, codec := NewAPIFactory()
+ tf.Printer = &testPrinter{}
+ tf.Client = &fake.RESTClient{
+ Codec: codec,
+ Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
+ switch p, m := req.URL.Path, req.Method; {
+ case p == "/namespaces/test/secrets" && m == "POST":
+ return &http.Response{StatusCode: 201, Body: objBody(codec, secretObject)}, nil
+ default:
+ t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
+ return nil, nil
+ }
+ }),
+ }
+ tf.Namespace = "test"
+ buf := bytes.NewBuffer([]byte{})
+ cmd := NewCmdCreateSecretDockerRegistry(f, buf)
+ cmd.Flags().Set("docker-username", "test-user")
+ cmd.Flags().Set("docker-password", "test-pass")
+ cmd.Flags().Set("docker-email", "test-email")
+ cmd.Flags().Set("output", "name")
+ cmd.Run(cmd, []string{secretObject.Name})
+ expectedOutput := "secret/" + secretObject.Name + "\n"
+ if buf.String() != expectedOutput {
+ t.Errorf("expected output: %s, but got: %s", buf.String(), expectedOutput)
+ }
+}
diff --git a/pkg/kubectl/cmd/util/factory.go b/pkg/kubectl/cmd/util/factory.go
index a1368290229..aadabfe43d9 100644
--- a/pkg/kubectl/cmd/util/factory.go
+++ b/pkg/kubectl/cmd/util/factory.go
@@ -106,6 +106,35 @@ type Factory struct {
EditorEnvs func() []string
}
+const (
+ RunV1GeneratorName = "run/v1"
+ RunPodV1GeneratorName = "run-pod/v1"
+ ServiceV1GeneratorName = "service/v1"
+ ServiceV2GeneratorName = "service/v2"
+ HorizontalPodAutoscalerV1Beta1GeneratorName = "horizontalpodautoscaler/v1beta1"
+ DeploymentV1Beta1GeneratorName = "deployment/v1beta1"
+ JobV1Beta1GeneratorName = "job/v1beta1"
+ NamespaceV1GeneratorName = "namespace/v1"
+ SecretV1GeneratorName = "secret/v1"
+ SecretForDockerRegistryV1GeneratorName = "secret-for-docker-registry/v1"
+)
+
+// DefaultGenerators returns the set of default generators for use in Factory instances
+func DefaultGenerators() map[string]kubectl.Generator {
+ return map[string]kubectl.Generator{
+ RunV1GeneratorName: kubectl.BasicReplicationController{},
+ RunPodV1GeneratorName: kubectl.BasicPod{},
+ ServiceV1GeneratorName: kubectl.ServiceGeneratorV1{},
+ ServiceV2GeneratorName: kubectl.ServiceGeneratorV2{},
+ HorizontalPodAutoscalerV1Beta1GeneratorName: kubectl.HorizontalPodAutoscalerV1Beta1{},
+ DeploymentV1Beta1GeneratorName: kubectl.DeploymentV1Beta1{},
+ JobV1Beta1GeneratorName: kubectl.JobV1Beta1{},
+ NamespaceV1GeneratorName: kubectl.NamespaceGeneratorV1{},
+ SecretV1GeneratorName: kubectl.SecretGeneratorV1{},
+ SecretForDockerRegistryV1GeneratorName: kubectl.SecretForDockerRegistryGeneratorV1{},
+ }
+}
+
// NewFactory creates a factory with the default Kubernetes resources defined
// if optionalClientConfig is nil, then flags will be bound to a new clientcmd.ClientConfig.
// if optionalClientConfig is not nil, then this factory will make use of it.
@@ -115,15 +144,7 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
flags := pflag.NewFlagSet("", pflag.ContinueOnError)
flags.SetNormalizeFunc(util.WarnWordSepNormalizeFunc) // Warn for "_" flags
- generators := map[string]kubectl.Generator{
- "run/v1": kubectl.BasicReplicationController{},
- "run-pod/v1": kubectl.BasicPod{},
- "service/v1": kubectl.ServiceGeneratorV1{},
- "service/v2": kubectl.ServiceGeneratorV2{},
- "horizontalpodautoscaler/v1beta1": kubectl.HorizontalPodAutoscalerV1Beta1{},
- "deployment/v1beta1": kubectl.DeploymentV1Beta1{},
- "job/v1beta1": kubectl.JobV1Beta1{},
- }
+ generators := DefaultGenerators()
clientConfig := optionalClientConfig
if optionalClientConfig == nil {
diff --git a/pkg/kubectl/cmd/util/helpers.go b/pkg/kubectl/cmd/util/helpers.go
index 3a7a15f1569..71c1983ccb0 100644
--- a/pkg/kubectl/cmd/util/helpers.go
+++ b/pkg/kubectl/cmd/util/helpers.go
@@ -304,6 +304,15 @@ func AddApplyAnnotationFlags(cmd *cobra.Command) {
cmd.Flags().Bool(ApplyAnnotationsFlag, false, "If true, the configuration of current object will be saved in its annotation. This is useful when you want to perform kubectl apply on this object in the future.")
}
+// AddGeneratorFlags adds flags common to resource generation commands
+// TODO: need to take a pass at other generator commands to use this set of flags
+func AddGeneratorFlags(cmd *cobra.Command, defaultGenerator string) {
+ cmd.Flags().String("generator", defaultGenerator, "The name of the API generator to use.")
+ cmd.Flags().Bool("dry-run", false, "If true, only print the object that would be sent, without sending it.")
+ cmd.Flags().StringP("output", "o", "", "Output format. One of: json|yaml|wide|name|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=... See golang template [http://golang.org/pkg/text/template/#pkg-overview] and jsonpath template [http://releases.k8s.io/HEAD/docs/user-guide/jsonpath.md].")
+ cmd.Flags().String("output-version", "", "Output the formatted object with the given version (default api-version).")
+}
+
func ReadConfigDataFromReader(reader io.Reader, source string) ([]byte, error) {
data, err := ioutil.ReadAll(reader)
if err != nil {
diff --git a/pkg/kubectl/generate.go b/pkg/kubectl/generate.go
index 3528e5e46e4..8c1ec434d9a 100644
--- a/pkg/kubectl/generate.go
+++ b/pkg/kubectl/generate.go
@@ -42,6 +42,12 @@ type Generator interface {
ParamNames() []GeneratorParam
}
+// StructuredGenerator is an interface for things that can generate API objects not using parameter injection
+type StructuredGenerator interface {
+ // StructuredGenerator creates an API object using pre-configured parameters
+ StructuredGenerate() (runtime.Object, error)
+}
+
func IsZero(i interface{}) bool {
if i == nil {
return true
diff --git a/pkg/kubectl/namespace.go b/pkg/kubectl/namespace.go
new file mode 100644
index 00000000000..c6011d38b43
--- /dev/null
+++ b/pkg/kubectl/namespace.go
@@ -0,0 +1,79 @@
+/*
+Copyright 2015 The Kubernetes Authors All rights reserved.
+
+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 (
+ "fmt"
+
+ "k8s.io/kubernetes/pkg/api"
+ "k8s.io/kubernetes/pkg/runtime"
+)
+
+// NamespaceGeneratorV1 supports stable generation of a namespace
+type NamespaceGeneratorV1 struct {
+ // Name of namespace
+ Name string
+}
+
+// Ensure it supports the generator pattern that uses parameter injection
+var _ Generator = &NamespaceGeneratorV1{}
+
+// Ensure it supports the generator pattern that uses parameters specified during construction
+var _ StructuredGenerator = &NamespaceGeneratorV1{}
+
+// Generate returns a namespace using the specified parameters
+func (g NamespaceGeneratorV1) Generate(genericParams map[string]interface{}) (runtime.Object, error) {
+ err := ValidateParams(g.ParamNames(), genericParams)
+ if err != nil {
+ return nil, err
+ }
+ params := map[string]string{}
+ for key, value := range genericParams {
+ strVal, isString := value.(string)
+ if !isString {
+ return nil, fmt.Errorf("expected string, saw %v for '%s'", value, key)
+ }
+ params[key] = strVal
+ }
+ delegate := &NamespaceGeneratorV1{Name: params["name"]}
+ return delegate.StructuredGenerate()
+}
+
+// ParamNames returns the set of supported input parameters when using the parameter injection generator pattern
+func (g NamespaceGeneratorV1) ParamNames() []GeneratorParam {
+ return []GeneratorParam{
+ {"name", true},
+ }
+}
+
+// StructuredGenerate outputs a namespace object using the configured fields
+func (g *NamespaceGeneratorV1) StructuredGenerate() (runtime.Object, error) {
+ if err := g.validate(); err != nil {
+ return nil, err
+ }
+ namespace := &api.Namespace{}
+ namespace.Name = g.Name
+ return namespace, nil
+}
+
+// validate validates required fields are set to support structured generation
+func (g *NamespaceGeneratorV1) validate() error {
+ if len(g.Name) == 0 {
+ return fmt.Errorf("name must be specified")
+ }
+ return nil
+}
diff --git a/pkg/kubectl/namespace_test.go b/pkg/kubectl/namespace_test.go
new file mode 100644
index 00000000000..b0445bd2999
--- /dev/null
+++ b/pkg/kubectl/namespace_test.go
@@ -0,0 +1,61 @@
+/*
+Copyright 2015 The Kubernetes Authors All rights reserved.
+
+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 (
+ "reflect"
+ "testing"
+
+ "k8s.io/kubernetes/pkg/api"
+)
+
+func TestNamespaceGenerate(t *testing.T) {
+ tests := []struct {
+ params map[string]interface{}
+ expected *api.Namespace
+ expectErr bool
+ }{
+ {
+ params: map[string]interface{}{
+ "name": "foo",
+ },
+ expected: &api.Namespace{
+ ObjectMeta: api.ObjectMeta{
+ Name: "foo",
+ },
+ },
+ expectErr: false,
+ },
+ {
+ params: map[string]interface{}{},
+ expectErr: true,
+ },
+ }
+ generator := NamespaceGeneratorV1{}
+ for _, test := range tests {
+ obj, err := generator.Generate(test.params)
+ if !test.expectErr && err != nil {
+ t.Errorf("unexpected error: %v", err)
+ }
+ if test.expectErr && err != nil {
+ continue
+ }
+ if !reflect.DeepEqual(obj.(*api.Namespace), test.expected) {
+ t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", test.expected, obj.(*api.Namespace))
+ }
+ }
+}
diff --git a/pkg/kubectl/secret.go b/pkg/kubectl/secret.go
new file mode 100644
index 00000000000..62de7900874
--- /dev/null
+++ b/pkg/kubectl/secret.go
@@ -0,0 +1,238 @@
+/*
+Copyright 2015 The Kubernetes Authors All rights reserved.
+
+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 (
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path"
+ "strings"
+
+ "k8s.io/kubernetes/pkg/api"
+ "k8s.io/kubernetes/pkg/api/validation"
+ "k8s.io/kubernetes/pkg/runtime"
+)
+
+// SecretGeneratorV1 supports stable generation of an opaque secret
+type SecretGeneratorV1 struct {
+ // Name of secret (required)
+ Name string
+ // Type of secret (optional)
+ Type string
+ // FileSources to derive the secret from (optional)
+ FileSources []string
+ // LiteralSources to derive the secret from (optional)
+ LiteralSources []string
+}
+
+// Ensure it supports the generator pattern that uses parameter injection
+var _ Generator = &SecretGeneratorV1{}
+
+// Ensure it supports the generator pattern that uses parameters specified during construction
+var _ StructuredGenerator = &SecretGeneratorV1{}
+
+// Generate returns a secret using the specified parameters
+func (s SecretGeneratorV1) Generate(genericParams map[string]interface{}) (runtime.Object, error) {
+ err := ValidateParams(s.ParamNames(), genericParams)
+ if err != nil {
+ return nil, err
+ }
+ delegate := &SecretGeneratorV1{}
+ fromFileStrings, found := genericParams["from-file"]
+ if found {
+ fromFileArray, isArray := fromFileStrings.([]string)
+ if !isArray {
+ return nil, fmt.Errorf("expected []string, found :%v", fromFileStrings)
+ }
+ delegate.FileSources = fromFileArray
+ delete(genericParams, "from-file")
+ }
+ fromLiteralStrings, found := genericParams["from-literal"]
+ if found {
+ fromLiteralArray, isArray := fromLiteralStrings.([]string)
+ if !isArray {
+ return nil, fmt.Errorf("expected []string, found :%v", fromFileStrings)
+ }
+ delegate.LiteralSources = fromLiteralArray
+ delete(genericParams, "from-literal")
+ }
+ params := map[string]string{}
+ for key, value := range genericParams {
+ strVal, isString := value.(string)
+ if !isString {
+ return nil, fmt.Errorf("expected string, saw %v for '%s'", value, key)
+ }
+ params[key] = strVal
+ }
+ delegate.Name = params["name"]
+ delegate.Type = params["type"]
+ return delegate.StructuredGenerate()
+}
+
+// ParamNames returns the set of supported input parameters when using the parameter injection generator pattern
+func (s SecretGeneratorV1) ParamNames() []GeneratorParam {
+ return []GeneratorParam{
+ {"name", true},
+ {"type", false},
+ {"from-file", false},
+ {"from-literal", false},
+ {"force", false},
+ }
+}
+
+// StructuredGenerate outputs a secret object using the configured fields
+func (s SecretGeneratorV1) StructuredGenerate() (runtime.Object, error) {
+ if err := s.validate(); err != nil {
+ return nil, err
+ }
+ secret := &api.Secret{}
+ secret.Name = s.Name
+ secret.Data = map[string][]byte{}
+ if len(s.Type) > 0 {
+ secret.Type = api.SecretType(s.Type)
+ }
+ if len(s.FileSources) > 0 {
+ if err := handleFromFileSources(secret, s.FileSources); err != nil {
+ return nil, err
+ }
+ }
+ if len(s.LiteralSources) > 0 {
+ if err := handleFromLiteralSources(secret, s.LiteralSources); err != nil {
+ return nil, err
+ }
+ }
+ return secret, nil
+}
+
+// validate validates required fields are set to support structured generation
+func (s SecretGeneratorV1) validate() error {
+ if len(s.Name) == 0 {
+ return fmt.Errorf("name must be specified")
+ }
+ return nil
+}
+
+// handleFromLiteralSources adds the specified literal source information into the provided secret
+func handleFromLiteralSources(secret *api.Secret, literalSources []string) error {
+ for _, literalSource := range literalSources {
+ keyName, value, err := parseLiteralSource(literalSource)
+ if err != nil {
+ return err
+ }
+ err = addKeyFromLiteralToSecret(secret, keyName, []byte(value))
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// handleFromFileSources adds the specified file source information into the provided secret
+func handleFromFileSources(secret *api.Secret, fileSources []string) error {
+ for _, fileSource := range fileSources {
+ keyName, filePath, err := parseFileSource(fileSource)
+ if err != nil {
+ return err
+ }
+ info, err := os.Stat(filePath)
+ if err != nil {
+ switch err := err.(type) {
+ case *os.PathError:
+ return fmt.Errorf("error reading %s: %v", filePath, err.Err)
+ default:
+ return fmt.Errorf("error reading %s: %v", filePath, err)
+ }
+ }
+ if info.IsDir() {
+ if strings.Contains(fileSource, "=") {
+ return fmt.Errorf("cannot give a key name for a directory path.")
+ }
+ fileList, err := ioutil.ReadDir(filePath)
+ if err != nil {
+ return fmt.Errorf("error listing files in %s: %v", filePath, err)
+ }
+ for _, item := range fileList {
+ itemPath := path.Join(filePath, item.Name())
+ if item.Mode().IsRegular() {
+ keyName = item.Name()
+ err = addKeyFromFileToSecret(secret, keyName, itemPath)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ } else {
+ err = addKeyFromFileToSecret(secret, keyName, filePath)
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ return nil
+}
+
+func addKeyFromFileToSecret(secret *api.Secret, keyName, filePath string) error {
+ data, err := ioutil.ReadFile(filePath)
+ if err != nil {
+ return err
+ }
+ return addKeyFromLiteralToSecret(secret, keyName, data)
+}
+
+func addKeyFromLiteralToSecret(secret *api.Secret, keyName string, data []byte) error {
+ if !validation.IsSecretKey(keyName) {
+ return fmt.Errorf("%v is not a valid key name for a secret", keyName)
+ }
+ if _, entryExists := secret.Data[keyName]; entryExists {
+ return fmt.Errorf("cannot add key %s, another key by that name already exists: %v.", keyName, secret.Data)
+ }
+ secret.Data[keyName] = data
+ return nil
+}
+
+// parseFileSource parses the source given. Acceptable formats include:
+// source-name=source-path, where source-name will become the key name and source-path is the path to the key file
+// source-path, where source-path is a path to a file or directory, and key names will default to file names
+// Key names cannot include '='.
+func parseFileSource(source string) (keyName, filePath string, err error) {
+ numSeparators := strings.Count(source, "=")
+ switch {
+ case numSeparators == 0:
+ return path.Base(source), source, nil
+ case numSeparators == 1 && strings.HasPrefix(source, "="):
+ return "", "", fmt.Errorf("key name for file path %v missing.", strings.TrimPrefix(source, "="))
+ case numSeparators == 1 && strings.HasSuffix(source, "="):
+ return "", "", fmt.Errorf("file path for key name %v missing.", strings.TrimSuffix(source, "="))
+ case numSeparators > 1:
+ return "", "", errors.New("Key names or file paths cannot contain '='.")
+ default:
+ components := strings.Split(source, "=")
+ return components[0], components[1], nil
+ }
+}
+
+// parseLiteralSource parses the source key=val pair
+func parseLiteralSource(source string) (keyName, value string, err error) {
+ items := strings.Split(source, "=")
+ if len(items) != 2 {
+ return "", "", fmt.Errorf("invalid literal source %v, expected key=value", source)
+ }
+ return items[0], items[1], nil
+}
diff --git a/pkg/kubectl/secret_for_docker_registry.go b/pkg/kubectl/secret_for_docker_registry.go
new file mode 100644
index 00000000000..773bde3865a
--- /dev/null
+++ b/pkg/kubectl/secret_for_docker_registry.go
@@ -0,0 +1,131 @@
+/*
+Copyright 2015 The Kubernetes Authors All rights reserved.
+
+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 (
+ "encoding/json"
+ "fmt"
+
+ "k8s.io/kubernetes/pkg/api"
+ "k8s.io/kubernetes/pkg/credentialprovider"
+ "k8s.io/kubernetes/pkg/runtime"
+)
+
+// SecretForDockerRegistryGeneratorV1 supports stable generation of a docker registry secret
+type SecretForDockerRegistryGeneratorV1 struct {
+ // Name of secret (required)
+ Name string
+ // Username for registry (required)
+ Username string
+ // Email for registry (required)
+ Email string
+ // Password for registry (required)
+ Password string
+ // Server for registry (required)
+ Server string
+}
+
+// Ensure it supports the generator pattern that uses parameter injection
+var _ Generator = &SecretForDockerRegistryGeneratorV1{}
+
+// Ensure it supports the generator pattern that uses parameters specified during construction
+var _ StructuredGenerator = &SecretForDockerRegistryGeneratorV1{}
+
+// Generate returns a secret using the specified parameters
+func (s SecretForDockerRegistryGeneratorV1) Generate(genericParams map[string]interface{}) (runtime.Object, error) {
+ err := ValidateParams(s.ParamNames(), genericParams)
+ if err != nil {
+ return nil, err
+ }
+ params := map[string]string{}
+ for key, value := range genericParams {
+ strVal, isString := value.(string)
+ if !isString {
+ return nil, fmt.Errorf("expected string, saw %v for '%s'", value, key)
+ }
+ params[key] = strVal
+ }
+ delegate := &SecretForDockerRegistryGeneratorV1{
+ Name: params["name"],
+ Username: params["docker-username"],
+ Email: params["docker-email"],
+ Password: params["docker-password"],
+ Server: params["docker-server"],
+ }
+ return delegate.StructuredGenerate()
+}
+
+// StructuredGenerate outputs a secret object using the configured fields
+func (s SecretForDockerRegistryGeneratorV1) StructuredGenerate() (runtime.Object, error) {
+ if err := s.validate(); err != nil {
+ return nil, err
+ }
+ dockercfgContent, err := handleDockercfgContent(s.Username, s.Password, s.Email, s.Server)
+ if err != nil {
+ return nil, err
+ }
+ secret := &api.Secret{}
+ secret.Name = s.Name
+ secret.Type = api.SecretTypeDockercfg
+ secret.Data = map[string][]byte{}
+ secret.Data[api.DockerConfigKey] = dockercfgContent
+ return secret, nil
+}
+
+// ParamNames returns the set of supported input parameters when using the parameter injection generator pattern
+func (s SecretForDockerRegistryGeneratorV1) ParamNames() []GeneratorParam {
+ return []GeneratorParam{
+ {"name", true},
+ {"docker-username", true},
+ {"docker-email", true},
+ {"docker-password", true},
+ {"docker-server", true},
+ }
+}
+
+// validate validates required fields are set to support structured generation
+func (s SecretForDockerRegistryGeneratorV1) validate() error {
+ if len(s.Name) == 0 {
+ return fmt.Errorf("name must be specified")
+ }
+ if len(s.Username) == 0 {
+ return fmt.Errorf("username must be specified")
+ }
+ if len(s.Email) == 0 {
+ return fmt.Errorf("email must be specified")
+ }
+ if len(s.Password) == 0 {
+ return fmt.Errorf("password must be specified")
+ }
+ if len(s.Server) == 0 {
+ return fmt.Errorf("server must be specified")
+ }
+ return nil
+}
+
+// handleDockercfgContent serializes a dockercfg json file
+func handleDockercfgContent(username, password, email, server string) ([]byte, error) {
+ dockercfgAuth := credentialprovider.DockerConfigEntry{
+ Username: username,
+ Password: password,
+ Email: email,
+ }
+
+ dockerCfg := map[string]credentialprovider.DockerConfigEntry{server: dockercfgAuth}
+
+ return json.Marshal(dockerCfg)
+}
diff --git a/pkg/kubectl/secret_for_docker_registry_test.go b/pkg/kubectl/secret_for_docker_registry_test.go
new file mode 100644
index 00000000000..65d8d397d7f
--- /dev/null
+++ b/pkg/kubectl/secret_for_docker_registry_test.go
@@ -0,0 +1,81 @@
+/*
+Copyright 2015 The Kubernetes Authors All rights reserved.
+
+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 (
+ "reflect"
+ "testing"
+
+ "k8s.io/kubernetes/pkg/api"
+)
+
+func TestSecretForDockerRegistryGenerate(t *testing.T) {
+ username, password, email, server := "test-user", "test-password", "test-user@example.org", "https://index.docker.io/v1/"
+ secretData, err := handleDockercfgContent(username, password, email, server)
+ if err != nil {
+ t.Errorf("unexpected error: %v", err)
+ }
+
+ tests := map[string]struct {
+ params map[string]interface{}
+ expected *api.Secret
+ expectErr bool
+ }{
+ "test-valid-use": {
+ params: map[string]interface{}{
+ "name": "foo",
+ "docker-server": server,
+ "docker-username": username,
+ "docker-password": password,
+ "docker-email": email,
+ },
+ expected: &api.Secret{
+ ObjectMeta: api.ObjectMeta{
+ Name: "foo",
+ },
+ Data: map[string][]byte{
+ api.DockerConfigKey: secretData,
+ },
+ Type: api.SecretTypeDockercfg,
+ },
+ expectErr: false,
+ },
+ "test-missing-required-param": {
+ params: map[string]interface{}{
+ "name": "foo",
+ "docker-server": server,
+ "docker-password": password,
+ "docker-email": email,
+ },
+ expectErr: true,
+ },
+ }
+
+ generator := SecretForDockerRegistryGeneratorV1{}
+ for _, test := range tests {
+ obj, err := generator.Generate(test.params)
+ if !test.expectErr && err != nil {
+ t.Errorf("unexpected error: %v", err)
+ }
+ if test.expectErr && err != nil {
+ continue
+ }
+ if !reflect.DeepEqual(obj.(*api.Secret), test.expected) {
+ t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", test.expected, obj.(*api.Secret))
+ }
+ }
+}
diff --git a/pkg/kubectl/secret_test.go b/pkg/kubectl/secret_test.go
new file mode 100644
index 00000000000..e713c991182
--- /dev/null
+++ b/pkg/kubectl/secret_test.go
@@ -0,0 +1,109 @@
+/*
+Copyright 2015 The Kubernetes Authors All rights reserved.
+
+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 (
+ "reflect"
+ "testing"
+
+ "k8s.io/kubernetes/pkg/api"
+)
+
+func TestSecretGenerate(t *testing.T) {
+ tests := []struct {
+ params map[string]interface{}
+ expected *api.Secret
+ expectErr bool
+ }{
+ {
+ params: map[string]interface{}{
+ "name": "foo",
+ },
+ expected: &api.Secret{
+ ObjectMeta: api.ObjectMeta{
+ Name: "foo",
+ },
+ Data: map[string][]byte{},
+ },
+ expectErr: false,
+ },
+ {
+ params: map[string]interface{}{
+ "name": "foo",
+ "type": "my-type",
+ },
+ expected: &api.Secret{
+ ObjectMeta: api.ObjectMeta{
+ Name: "foo",
+ },
+ Data: map[string][]byte{},
+ Type: "my-type",
+ },
+ expectErr: false,
+ },
+ {
+ params: map[string]interface{}{
+ "name": "foo",
+ "from-literal": []string{"key1=value1", "key2=value2"},
+ },
+ expected: &api.Secret{
+ ObjectMeta: api.ObjectMeta{
+ Name: "foo",
+ },
+ Data: map[string][]byte{
+ "key1": []byte("value1"),
+ "key2": []byte("value2"),
+ },
+ },
+ expectErr: false,
+ },
+ {
+ params: map[string]interface{}{
+ "name": "foo",
+ "from-literal": []string{"key1value1"},
+ },
+ expectErr: true,
+ },
+ {
+ params: map[string]interface{}{
+ "name": "foo",
+ "from-file": []string{"key1=/file=2"},
+ },
+ expectErr: true,
+ },
+ {
+ params: map[string]interface{}{
+ "name": "foo",
+ "from-file": []string{"key1==value"},
+ },
+ expectErr: true,
+ },
+ }
+ generator := SecretGeneratorV1{}
+ for _, test := range tests {
+ obj, err := generator.Generate(test.params)
+ if !test.expectErr && err != nil {
+ t.Errorf("unexpected error: %v", err)
+ }
+ if test.expectErr && err != nil {
+ continue
+ }
+ if !reflect.DeepEqual(obj.(*api.Secret), test.expected) {
+ t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", test.expected, obj.(*api.Secret))
+ }
+ }
+}