# Kubectl Conventions

Updated: 3/23/2017

**Table of Contents**

- [Kubectl Conventions](#kubectl-conventions)
  - [Principles](#principles)
  - [Command conventions](#command-conventions)
    - [Create commands](#create-commands)
    - [Rules for extending special resource alias - "all"](#rules-for-extending-special-resource-alias---all)
  - [Flag conventions](#flag-conventions)
  - [Output conventions](#output-conventions)
  - [Documentation conventions](#documentation-conventions)
  - [kubectl Factory conventions](#kubectl-Factory-conventions)
  - [Command implementation conventions](#command-implementation-conventions)
  - [Exit code conventions](#exit-code-conventions)
  - [Generators](#generators)


## Principles

* Strive for consistency across commands

* Explicit should always override implicit

  * Environment variables should override default values

  * Command-line flags should override default values and environment variables

    * `--namespace` should also override the value specified in a specified
resource

* Most kubectl commands should be able to operate in bulk on resources, of mixed types.

* Kubectl should not make any decisions based on its nor the server's release version string. Instead, API
  discovery and/or OpenAPI should be used to determine available features.

* We currently only guarantee one release of version skew is supported, but we strive to make old releases of kubectl 
  continue to work with newer servers in compliance with our API compatibility guarantees. This means, for instance, that
  kubectl should not fully parse objects returned by the server into full Go types and then re-encode them, since that
  would drop newly added fields. ([#3955](https://github.com/kubernetes/kubernetes/issues/3955))
  
* General-purpose kubectl commands (e.g., get, delete, create -f, replace, patch, apply) should work for all resource types,
  even those not present when that release of kubectl was built, such as APIs added in newer releases, aggregated APIs,
  and third-party resources.

* While functionality may be added to kubectl out of expedience, commonly needed functionality should be provided by
  the server to make it easily accessible to all API clients. ([#12143](https://github.com/kubernetes/kubernetes/issues/12143))
  
* Remaining non-trivial functionality remaining in kubectl should be made available to other clients via libraries
  ([#7311](https://github.com/kubernetes/kubernetes/issues/7311))
  
## Command conventions

* Command names are all lowercase, and hyphenated if multiple words.

* kubectl VERB NOUNs for commands that apply to multiple resource types.

* Command itself should not have built-in aliases.

* NOUNs may be specified as `TYPE name1 name2` or `TYPE/name1 TYPE/name2` or
`TYPE1,TYPE2,TYPE3/name1`; TYPE is omitted when only a single type is expected.

* Resource types are all lowercase, with no hyphens; both singular and plural
forms are accepted.

* NOUNs may also be specified by one or more file arguments: `-f file1 -f file2
...`

* Resource types may have 2- or 3-letter aliases.

* Business logic should be decoupled from the command framework, so that it can
be reused independently of kubectl, cobra, etc.
  * Ideally, commonly needed functionality would be implemented server-side in
order to avoid problems typical of "fat" clients and to make it readily
available to non-Go clients.

* Commands that generate resources, such as `run` or `expose`, should obey
specific conventions, see [generators](#generators).

* A command group (e.g., `kubectl config`) may be used to group related
non-standard commands, such as custom generators, mutations, and computations.


### Create commands

`kubectl create <resource>` commands fill the gap between "I want to try
Kubernetes, but I don't know or care what gets created" (`kubectl run`) and "I
want to create exactly this" (author yaml and run `kubectl create -f`). They
provide an easy way to create a valid object without having to know the vagaries
of particular kinds, nested fields, and object key typos that are ignored by the
yaml/json parser. Because editing an already created object is easier than
authoring one from scratch, these commands only need to have enough parameters
to create a valid object and set common immutable fields.  It should default as
much as is reasonably possible. Once that valid object is created, it can be
further manipulated using `kubectl edit` or the eventual `kubectl set` commands.

`kubectl create <resource> <special-case>` commands help in cases where you need
to perform non-trivial configuration generation/transformation tailored for a
common use case. `kubectl create secret` is a good example, there's a `generic`
flavor with keys mapping to files, then there's a `docker-registry` flavor that
is tailored for creating an image pull secret, and there's a `tls` flavor for
creating tls secrets. You create these as separate commands to get distinct
flags and separate help that is tailored for the particular usage.


### Rules for extending special resource alias - "all"

Here are the rules to add a new resource to the `kubectl get all` output.

* No cluster scoped resources

* No namespace admin level resources (limits, quota, policy, authorization
rules)

* No resources that are potentially unrecoverable (secrets and pvc)

* Resources that are considered "similar" to #3 should be grouped
the same (configmaps)


## Flag conventions

* Flags are all lowercase, with words separated by hyphens

* Flag names and single-character aliases should have the same meaning across
all commands

* Flag descriptions should start with an uppercase letter and not have a
period at the end of a sentence

* Command-line flags corresponding to API fields should accept API enums
exactly (e.g., `--restart=Always`)

* Do not reuse flags for different semantic purposes, and do not use different
flag names for the same semantic purpose -- grep for `"Flags()"` before adding a
new flag

* Use short flags sparingly, only for the most frequently used options, prefer
lowercase over uppercase for the most common cases, try to stick to well known
conventions for UNIX commands and/or Docker, where they exist, and update this
list when adding new short flags

  * `-f`: Resource file
    * also used for `--follow` in `logs`, but should be deprecated in favor of `-F`
  * `-n`: Namespace scope
  * `-l`: Label selector
    * also used for `--labels` in `expose`, but should be deprecated
  * `-L`: Label columns
  * `-c`: Container
    * also used for `--client` in `version`, but should be deprecated
  * `-i`: Attach stdin
  * `-t`: Allocate TTY
  * `-w`: Watch (currently also used for `--www` in `proxy`, but should be deprecated)
  * `-p`: Previous
    * also used for `--pod` in `exec`, but deprecated
    * also used for `--patch` in `patch`, but should be deprecated
    * also used for `--port` in `proxy`, but should be deprecated
  * `-P`: Static file prefix in `proxy`, but should be deprecated
  * `-r`: Replicas
  * `-u`: Unix socket
  * `-v`: Verbose logging level


* `--dry-run`: Don't modify the live state; simulate the mutation and display
the output. All mutations should support it.

* `--local`: Don't contact the server; just do local read, transformation,
generation, etc., and display the output

* `--output-version=...`: Convert the output to a different API group/version

* `--short`: Output a compact summary of normal output; the format is subject
to change and is optimized for reading not parsing.

* `--validate`: Validate the resource schema

## Output conventions

* By default, output is intended for humans rather than programs
  * However, affordances are made for simple parsing of `get` output

* Only errors should be directed to stderr

* `get` commands should output one row per resource, and one resource per row

  * Column titles and values should not contain spaces in order to facilitate
commands that break lines into fields: cut, awk, etc. Instead, use `-` as the
word separator.

  * By default, `get` output should fit within about 80 columns

    * Eventually we could perhaps auto-detect width
    * `-o wide` may be used to display additional columns


  * The first column should be the resource name, titled `NAME` (may change this
to an abbreviation of resource type)

  * NAMESPACE should be displayed as the first column when --all-namespaces is
specified

  * The last default column should be time since creation, titled `AGE`

  * `-Lkey` should append a column containing the value of label with key `key`,
with `<none>` if not present

  * json, yaml, Go template, and jsonpath template formats should be supported
and encouraged for subsequent processing

      * Users should use --api-version or --output-version to ensure the output
uses the version they expect


* `describe` commands may output on multiple lines and may include information
from related resources, such as events. Describe should add additional
information from related resources that a normal user may need to know - if a
user would always run "describe resource1" and the immediately want to run a
"get type2" or "describe resource2", consider including that info. Examples,
persistent volume claims for pods that reference claims, events for most
resources, nodes and the pods scheduled on them. When fetching related
resources, a targeted field selector should be used in favor of client side
filtering of related resources.

* For fields that can be explicitly unset (booleans, integers, structs), the
output should say `<unset>`. Likewise, for arrays `<none>` should be used; for
external IP, `<nodes>` should be used; for load balancer, `<pending>` should be
used.  Lastly `<unknown>` should be used where unrecognized field type was
specified.

* Mutations should output TYPE/name verbed by default, where TYPE is singular;
`-o name` may be used to just display TYPE/name, which may be used to specify
resources in other commands

## Documentation conventions

* Commands are documented using Cobra; docs are then auto-generated by
`hack/update-generated-docs.sh`.

  * Use should contain a short usage string for the most common use case(s), not
an exhaustive specification

  * Short should contain a one-line explanation of what the command does
    * Short descriptions should start with an uppercase case letter and not
    have a period at the end of a sentence
    * Short descriptions should (if possible) start with a first person
    (singular present tense) verb

  * Long may contain multiple lines, including additional information about
input, output, commonly used flags, etc.
    * Long descriptions should use proper grammar, start with an uppercase
    letter and have a period at the end of a sentence


  * Example should contain examples
    * A comment should precede each example command. Comment should start with
      an uppercase letter
    * Command examples should not include a `$` prefix

* Use "FILENAME" for filenames

* Use "TYPE" for the particular flavor of resource type accepted by kubectl,
rather than "RESOURCE" or "KIND"

* Use "NAME" for resource names

## kubectl Factory conventions

The kubectl `Factory` is a large interface which is used to provide access to clients,
polymorphic inspection, and polymorphic mutation.  The `Factory` is layered in
"rings" in which one ring may reference inner rings, but not peers or outer rings.
This is done to allow composition by extenders.

In order for composers to be able to provide alternative factory implementations
they need to provide low level pieces of *certain* functions so that when the factory
calls back into itself it uses the custom version of the function.  Rather than try
to enumerate everything that someone would want to override we split the factory into
rings, where each ring can depend on methods an earlier ring, but cannot depend upon
peer methods in its own ring.


## Command implementation conventions

For every command there should be a `NewCmd<CommandName>` function that creates
the command and returns a pointer to a `cobra.Command`, which can later be added
to other parent commands to compose the structure tree. There should also be a
`<CommandName>Options` struct with a variable to every flag and argument
declared by the command (and any other variable required for the command to
run). This makes tests and mocking easier. The struct ideally exposes three
methods:

* `Complete`: Completes the struct fields with values that may or may not be
directly provided by the user, for example, by flags pointers, by the `args`
slice, by using the Factory, etc.

* `Validate`: performs validation on the struct fields and returns appropriate
errors.

* `Run<CommandName>`: runs the actual logic of the command, taking as assumption
that the struct is complete with all required values to run, and they are valid.

Sample command skeleton:

```go
// MineRecommendedName is the recommended command name for kubectl mine.
const MineRecommendedName = "mine"

// Long command description and examples.
var (
  mineLong = templates.LongDesc(`
    mine which is described here
    with lots of details.`)

  mineExample = templates.Examples(`
    # Run my command's first action
    kubectl mine first_action

    # Run my command's second action on latest stuff
    kubectl mine second_action --flag`)
)

// MineOptions contains all the options for running the mine cli command.
type MineOptions struct {
  mineLatest bool
}

// NewCmdMine implements the kubectl mine command.
func NewCmdMine(parent, name string, f *cmdutil.Factory, out io.Writer) *cobra.Command {
  opts := &MineOptions{}

  cmd := &cobra.Command{
    Use:     fmt.Sprintf("%s [--latest]", name),
    Short:   "Run my command",
    Long:    mineLong,
    Example: fmt.Sprintf(mineExample, parent+" "+name),
    Run: func(cmd *cobra.Command, args []string) {
      if err := opts.Complete(f, cmd, args, out); err != nil {
        cmdutil.CheckErr(err)
      }
      if err := opts.Validate(); err != nil {
        cmdutil.CheckErr(cmdutil.UsageError(cmd, err.Error()))
      }
      if err := opts.RunMine(); err != nil {
        cmdutil.CheckErr(err)
      }
    },
  }

  cmd.Flags().BoolVar(&options.mineLatest, "latest", false, "Use latest stuff")
  return cmd
}

// Complete completes all the required options for mine.
func (o *MineOptions) Complete(f *cmdutil.Factory, cmd *cobra.Command, args []string, out io.Writer) error {
  return nil
}

// Validate validates all the required options for mine.
func (o MineOptions) Validate() error {
  return nil
}

// RunMine implements all the necessary functionality for mine.
func (o MineOptions) RunMine() error {
  return nil
}
```

The `Run<CommandName>` method should contain the business logic of the command
and as noted in [command conventions](#command-conventions), ideally that logic
should exist server-side so any client could take advantage of it. Notice that
this is not a mandatory structure and not every command is implemented this way,
but this is a nice convention so try to be compliant with it. As an example,
have a look at how [kubectl logs](https://git.k8s.io/kubernetes/pkg/kubectl/cmd/logs/logs.go) is implemented.

## Exit code conventions

Generally, for all the command exit code, result of `zero` means success and `non-zero` means errors.

For idempotent ("make-it-so") commands, we should return `zero` when success even if no changes were provided, user can request treating "make-it-so" as "already-so" via flag `--error-unchanged` to make it return `non-zero` exit code.

For non-idempotent ("already-so") commands, we should return `non-zero` by default, user can request treating "already-so" as "make-it-so" via flag `--ignore-unchanged` to make it return `zero` exit code.


| Exit Code Number | Meaning | Enable |
| :---             | :---    | :---    |
| 0                | Command exited success  | By default, By flag `--ignore-unchanged` |
| 1                | Command exited for general errors  | By default |
| 3                | Command was successful, but the user requested a distinct exit code when no change was made | By flag `--error-unchanged`|

## Generators

Generators are kubectl commands that generate resources based on a set of inputs
(other resources, flags, or a combination of both).

The point of generators is:

* to enable users using kubectl in a scripted fashion to pin to a particular
behavior which may change in the future. Explicit use of a generator will always
guarantee that the expected behavior stays the same.

* to enable potential expansion of the generated resources for scenarios other
than just creation, similar to how -f is supported for most general-purpose
commands.

Generator commands should obey the following conventions:

* A `--generator` flag should be defined. Users then can choose between
different generators, if the command supports them (for example, `kubectl run`
currently supports generators for pods, jobs, replication controllers, and
deployments), or between different versions of a generator so that users
depending on a specific behavior may pin to that version (for example, `kubectl
expose` currently supports two different versions of a service generator).

* Generation should be decoupled from creation. A generator should implement the
`kubectl.StructuredGenerator` interface and have no dependencies on cobra or the
Factory. See, for example, how the first version of the namespace generator is
defined:

```go
// NamespaceGeneratorV1 supports stable generation of a namespace
type NamespaceGeneratorV1 struct {
  // Name of namespace
  Name string
}

// Ensure it supports the generator pattern that uses parameters specified during construction
var _ StructuredGenerator = &NamespaceGeneratorV1{}

// 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
}
```

The generator struct (`NamespaceGeneratorV1`) holds the necessary fields for
namespace generation. It also satisfies the `kubectl.StructuredGenerator`
interface by implementing the `StructuredGenerate() (runtime.Object, error)`
method which configures the generated namespace that callers of the generator
(`kubectl create namespace` in our case) need to create.

* `--dry-run` should output the resource that would be created, without
creating it.

