Proposal for new kubecfg design (kubecfg2)

*The attached commit is for prototype/demonstration purposes only and not yet ready to be merged.*

### Intent

The intent of this pull request is to propose a design for the present and future of kubecfg. The conversation from #1167 was the primary input into this design. The idea is to have kubecfg solve two use cases:

1. Provide a great user experience to view the current status of a Kubernetes cluster and to execute simple commands on the cluster.
1. Provide a tool which will accept configuration with generic resources to submit changes to and diff against a Kubernetes cluster.

The problem with the current design is that it is too generic to effectively support (1). The proposed redesign enables custom commands per resource (e.g. kubecfg pods, kubecfg services, etc.) but generic subcommands to satisfy (2) (kubecfg submit, kubecfg diff, kubecfg reconcile, etc.).

### Proposed set of subcommands

*Only a subset of these have been implemented in the attached commit.*

* `kubecfg2` - Parent command.
  * `pods`
    * `list [<id>]` - List pods in a column-oriented view (see [Examples](#examples) below). By default, the first argument passed in acts as a filter by ID.
    * `get <id>` - List info about a pod in a row-oriented view. Designed to show more metadata about a given pod, and over time can be enhanced to make navigating the cluster from a given pod very easy. Currently I'm adding a list of any replication controllers whose selectors match (and therefore who control) the selected pod.
    * `delete <id>` - Delete a pod.
    * `create [-f <filename>]` - In the future we can accept directories or even data from stdin.
  * `rc` - For replication controllers. Happy to use a different abbreviation but replicationControllers seemed too long.
    * `list [<id>]`
    * `get <id>` - RC's `get` command could become extremely rich. For now I've added Pods Status which queries for pods under this replication controller and shows counts for running, waiting and terminated, but in the future you could do diffs against the controller's PodTemplate and show counts for matching and non-matching pods. You could also show the first 3-4 pod ID's per category and then show &lt;X more ...&gt;, making debugging even easier.
    * `create [-f <filename>]`
    * `update [-f <filename>]`
    * `delete <id>` - I have removed the delete/stop/rm replication controller confusion in favor of just `delete` and `resize`, where delete takes an optional --force flag if replicas > 0.
    * `resize <id> <replicas>`
    * *Removed* `rollingupdate <controller> <image> <time>` - I've included this here for parity but I would like to propose taking it out. This is the one command that I don't think belongs in kubecfg ... it's too long-running, fraught with edge cases, and in reality would probably want to take more into consideration (like fluctuations in metrics, % of pods that come up successfully, etc.). I think this level of functionality belongs in an independent client that uses the API that can look at more components in the infrastructure than just kubernetes.
  * `minions`
    * `list [<id>]`
    * `get <id>`
  * `services`
    * `list [<id>]`
    * `get <id>`
    * `create [-f <filename>]`
    * `update [-f <filename>]`
    * `delete <id>`
    * *Postponed* `resolve <id>` - Just an idea, but it could give you a random IP/port combination to connect to. May be useful for quickly locating a node to test for a given service.
  * *Postponed* `submit [<filename>...]` - This command exists to satisfy the second use case above. Reconcile and submit any changes from a given set of config(s), from files or from stdin. If you had an entire directory tree of files that had configs that represented your cluster state, you could use this command to submit them all to either create or update your cluster.
  * *Postponed* `diff [<filename>...]` - A dry-run version of `submit`.
  * `run [-p <port spec>] <image> <replicas> <controller>` - Same as today.

### Examples

Here is what the current commit produces:

*These examples are out of date - see [this comment](https://github.com/GoogleCloudPlatform/kubernetes/pull/1325#issuecomment-56786115) for the latest.*

```
$ kubecfg2
kubecfg2 controls the Kubernetes cluster manager.

Find more information at https://github.com/GoogleCloudPlatform/kubernetes.

Usage:
  kubecfg2 [command]

Available Commands:
  version                   Print version of client and server
  pods                      List, inspect and modify pods
  rc                        List, inspect and modify replication controllers
  help [command]            Help about any command

 Available Flags:
  -a, --auth="/Users/sam/.kubernetes_auth": Path to the auth info file. If missing, prompt the user. Only used if doing https.
      --help=false: help for kubecfg2
  -h, --host="": Kubernetes apiserver to connect to
  -m, --match-version=false: Require server version to match client version

Use "kubecfg2 help [command]" for more information about that command.

```
```
$ kubecfg2 help pods list
List one or more pods. Pass in an ID to filter.

Usage:
  kubecfg2 pods list [<id>] [flags]

 Available Flags:
  -a, --auth="/Users/sam/.kubernetes_auth": Path to the auth info file. If missing, prompt the user. Only used if doing https.
      --help=false: help for list
  -h, --host="": Kubernetes apiserver to connect to
  -m, --match-version=false: Require server version to match client version
  -l, --selector="": Selector (label query) to filter on


Use "kubecfg2 help [command]" for more information about that command.

```
```
$ kubecfg2 pods list
ID                                      IMAGE(S)                HOST            LABELS                                  STATUS
4893ea09-3d0d-11e4-b3ad-0800279696e1    dockerfile/nginx        127.0.0.1/      replicationController=MyNginxController Running
48943371-3d0d-11e4-b3ad-0800279696e1    dockerfile/nginx        127.0.0.1/      replicationController=MyNginxController Running
```
```
$ kubecfg2 pods list 4893ea09-3d0d-11e4-b3ad-0800279696e1
ID                                      IMAGE(S)                HOST            LABELS                                  STATUS
4893ea09-3d0d-11e4-b3ad-0800279696e1    dockerfile/nginx        127.0.0.1/      replicationController=MyNginxController Running
```
```
$ kubecfg2 pods get 4893ea09-3d0d-11e4-b3ad-0800279696e1
ID:                             4893ea09-3d0d-11e4-b3ad-0800279696e1
Image(s):                       dockerfile/nginx
Host:                           127.0.0.1/
Labels:                         replicationController=MyNginxController
Status:                         Running
Replication Controllers:        MyNginxController (2/2 replicas created)
```
```
$ kubecfg2 rc list
ID                      IMAGE(S)                SELECTOR                                REPLICAS
MyNginxController       dockerfile/nginx        replicationController=MyNginxController 2
```
```
$ kubecfg2 rc get MyNginxController
ID:             MyNginxController
Image(s):       dockerfile/nginx
Selector:       replicationController=MyNginxController
Labels:         <none>
Replicas:       2 current / 2 desired
Pods Status:    2 running / 0 waiting / 0 terminated
```

### Other notes

* I am currently using [spf13/cobra](https://github.com/spf13/cobra) but am also considering [codegangsta/cli](https://github.com/codegangsta/cli). The latter may allow us to write out the command definitions in a cleaner way and support bash autocompletion, but the former allows persistent flags. Open to using either one.
* Some of these commands (especially `get` commands that show a lot of info) may result in lots of queries to the server. There are several ways to handle this: (1) don't consider it an issue, (2) offer a "succinct mode" that tries to do as little as possible and (3) over time backport functionality that is particularly useful directly into apiserver as new API endpoints. Especially with (3), you could consider kubecfg a proving ground for new convenience functionality to see whether it's worth implementing in apiserver directly.

### File layout

* cmd/kubecfg2/kubecfg2.go - All cobra and CLI-related code remains in this file/package.
* pkg/kubecfg2/&lt;subcommand&gt;.go - All logic per subcommand lives in one file per subcommand.
* pkg/kubecfg2/kubecfg2.go - Common functions used by cmd/kubecfg2 and pkg/kubecfg2 packages.

### Open Questions
* Can we leave rollingupdate out of this version for the merge? If it's needed for demo purposes, can it be reimplemented somewhere outside of this tool?
* @erictune pointed out that `get` is not the best name for above. `info` and `details` are other options but ideas here are welcome.

When you compile the client today, you're importing api/latest which references all of the versions of an API which the code supports at the time you compile.  So as long as that client binary exists on disk, it will be able to convert any of those versions between each other (more or less).  Here's a hypothetical timeline:

1. we compile a client for 0.4.0 which supports v1beta1, v1beta2, and v1beta3.  The current default api version is v1beta1
2. user writes a bash script that says `kubectl ... --format=template --template="{{ .ID }}`.  That just happens to use v1beta1
3. we update to 0.5.0 and drop support for v1beta1 and v1beta2 in the server
4. user tries to connect to a new server (without upgrading his client) and the default API version now becomes v1beta3 because that's the common overlap between the two
5. user's bash script breaks because we changed `ID` to `Name`

We don't support negotiation today but it's inevitable - once we do that, some variant of this scenario will happen.

It doesn't cost us much to maintain old conversions (v1beta1/2 will probably get the boot just because they're too early) so in some distant future we could still have very old clients talking to very new servers, where scripts can lock in the old version.  So --api-version will likely become much different than the --format-api-version (or whatever it might be called).

----- Original Message -----
> > +See the License for the specific language governing permissions and
> > +limitations under the License.
> > +*/
> > +
> > +package cmd
> > +
> > +import (
> > +	"io"
> > +
> > +	"github.com/GoogleCloudPlatform/kubernetes/pkg/kubecfg"
> > +	"github.com/spf13/cobra"
> > +)
> > +
> > +func NewCmdGet(out io.Writer) *cobra.Command {
> > +	cmd := &cobra.Command{
> > +		Use:   "get [[-f|--format=]table|json|yaml|template] [-t
> > <file>|--template=<file>] <resource> [<id>]",
> 
> So are you saying that the client will always have the ability to convert
> %arbitrary_server_version% to %desired_client_version% on its own? Will that
> always be guaranteed?
> 
> ---
> Reply to this email directly or view it on GitHub:
> https://github.com/GoogleCloudPlatform/kubernetes/pull/1325/files#r18661405