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 @@ + + + + +WARNING +WARNING +WARNING +WARNING +WARNING + +

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 + + +[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_create_namespace.md?pixel)]() + 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 @@ + + + + +WARNING +WARNING +WARNING +WARNING +WARNING + +

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 + + +[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_create_secret.md?pixel)]() + 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 @@ + + + + +WARNING +WARNING +WARNING +WARNING +WARNING + +

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 + + +[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_create_secret_docker-registry.md?pixel)]() + 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 @@ + + + + +WARNING +WARNING +WARNING +WARNING +WARNING + +

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 + + +[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_create_secret_generic.md?pixel)]() + 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)) + } + } +}